From 8a180ad417c26429cd3774c0046165c40ad1010a Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 28 Apr 2016 09:04:35 +0000
Subject: [PATCH] LDAPAuthenticationHandler.java: Remove code duplication

---
 opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPClientConnection.java     |  304 +++---
 opendj-server-legacy/src/test/java/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java |  565 +++--------
 opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPPasswordModify.java                |   47 
 opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPAuthenticationHandler.java         | 1964 +++++++++-------------------------------
 4 files changed, 812 insertions(+), 2,068 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPClientConnection.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPClientConnection.java
index 02380e0..f6c1719 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPClientConnection.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -16,12 +16,24 @@
  */
 package org.opends.server.protocols.ldap;
 
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.messages.ProtocolMessages.*;
+import static org.opends.server.core.DirectoryServer.*;
+import static org.opends.server.loggers.AccessLogger.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.nio.ByteBuffer;
-import java.nio.channels.*;
+import java.nio.channels.ByteChannel;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
 import java.security.cert.Certificate;
 import java.util.Collection;
 import java.util.Iterator;
@@ -45,23 +57,38 @@
 import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ConnectionHandler;
-import org.opends.server.core.*;
+import org.opends.server.core.AbandonOperationBasis;
+import org.opends.server.core.AddOperationBasis;
+import org.opends.server.core.BindOperationBasis;
+import org.opends.server.core.CompareOperationBasis;
+import org.opends.server.core.DeleteOperationBasis;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ExtendedOperationBasis;
+import org.opends.server.core.ModifyDNOperationBasis;
+import org.opends.server.core.ModifyOperationBasis;
+import org.opends.server.core.PersistentSearch;
+import org.opends.server.core.PluginConfigManager;
+import org.opends.server.core.SearchOperation;
+import org.opends.server.core.SearchOperationBasis;
+import org.opends.server.core.UnbindOperationBasis;
 import org.opends.server.extensions.ConnectionSecurityProvider;
 import org.opends.server.extensions.RedirectingByteChannel;
 import org.opends.server.extensions.TLSByteChannel;
 import org.opends.server.extensions.TLSCapableConnection;
-import org.opends.server.types.*;
+import org.opends.server.types.AuthenticationType;
+import org.opends.server.types.CancelRequest;
+import org.opends.server.types.CancelResult;
+import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DisconnectReason;
+import org.opends.server.types.IntermediateResponse;
+import org.opends.server.types.Operation;
+import org.opends.server.types.OperationType;
+import org.opends.server.types.SearchResultEntry;
+import org.opends.server.types.SearchResultReference;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.util.TimeThread;
 
-import static org.opends.messages.CoreMessages.*;
-import static org.opends.messages.ProtocolMessages.*;
-import static org.opends.server.core.DirectoryServer.*;
-import static org.opends.server.loggers.AccessLogger.*;
-import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
 /**
  * This class defines an LDAP client connection, which is a type of
  * client connection that will be accepted by an instance of the LDAP
@@ -231,13 +258,9 @@
               // We've been blocked for too long.
               throw new ClosedChannelException();
             }
-            else
-            {
-              waitTime = stopTime - currentTime;
-            }
+            waitTime = stopTime - currentTime;
 
-            Iterator<SelectionKey> iterator = selector.selectedKeys()
-                .iterator();
+            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
             while (iterator.hasNext())
             {
               SelectionKey k = iterator.next();
@@ -375,7 +398,7 @@
   private final LDAPConnectionHandler connectionHandler;
   /** The statistics tracker associated with this client connection. */
   private final LDAPStatistics statTracker;
-  private boolean useNanoTime;
+  private final boolean useNanoTime;
 
   /** The connection ID assigned to this connection. */
   private final long connectionID;
@@ -395,7 +418,7 @@
   /** The string representation of the address of the server to which the client has connected. */
   private final String serverAddress;
 
-  private ASN1ByteChannelReader asn1Reader;
+  private final ASN1ByteChannelReader asn1Reader;
   private final int bufferSize;
   private final RedirectingByteChannel saslChannel;
   private final RedirectingByteChannel tlsChannel;
@@ -440,20 +463,20 @@
     serverPort = socket.getLocalPort();
 
     statTracker = this.connectionHandler.getStatTracker();
-
     if (keepStats)
     {
       statTracker.updateConnect();
       this.useNanoTime=DirectoryServer.getUseNanoTime();
     }
+    else
+    {
+      this.useNanoTime = false;
+    }
 
     bufferSize = connectionHandler.getBufferSize();
 
-    tlsChannel =
-        RedirectingByteChannel.getRedirectingByteChannel(
-            timeoutClientChannel);
-    saslChannel =
-        RedirectingByteChannel.getRedirectingByteChannel(tlsChannel);
+    tlsChannel = RedirectingByteChannel.getRedirectingByteChannel(timeoutClientChannel);
+    saslChannel = RedirectingByteChannel.getRedirectingByteChannel(tlsChannel);
     this.asn1Reader = new ASN1ByteChannelReader(saslChannel, bufferSize, connectionHandler.getMaxRequestSize());
 
     if (connectionHandler.useSSL())
@@ -981,20 +1004,20 @@
     // Indicate that this connection is no longer valid.
     connectionValid = false;
 
+    final LocalizableMessage cancelMessage;
     if (message != null)
     {
-      LocalizableMessageBuilder msgBuilder = new LocalizableMessageBuilder();
-      msgBuilder.append(disconnectReason.getClosureMessage());
-      msgBuilder.append(": ");
-      msgBuilder.append(message);
-      cancelAllOperations(new CancelRequest(true, msgBuilder
-          .toMessage()));
+      cancelMessage = new LocalizableMessageBuilder()
+          .append(disconnectReason.getClosureMessage())
+          .append(": ")
+          .append(message)
+          .toMessage();
     }
     else
     {
-      cancelAllOperations(new CancelRequest(true, disconnectReason
-          .getClosureMessage()));
+      cancelMessage = disconnectReason.getClosureMessage();
     }
+    cancelAllOperations(new CancelRequest(true, cancelMessage));
     finalizeConnectionInternal();
 
     // If there is a write selector for this connection, then close it.
@@ -1008,45 +1031,8 @@
     {
       try
       {
-        int resultCode;
-        switch (disconnectReason)
-        {
-        case PROTOCOL_ERROR:
-          resultCode = LDAPResultCode.PROTOCOL_ERROR;
-          break;
-        case SERVER_SHUTDOWN:
-          resultCode = LDAPResultCode.UNAVAILABLE;
-          break;
-        case SERVER_ERROR:
-          resultCode = DirectoryServer.getServerErrorResultCode().intValue();
-          break;
-        case ADMIN_LIMIT_EXCEEDED:
-        case IDLE_TIME_LIMIT_EXCEEDED:
-        case MAX_REQUEST_SIZE_EXCEEDED:
-        case IO_TIMEOUT:
-          resultCode = LDAPResultCode.ADMIN_LIMIT_EXCEEDED;
-          break;
-        case CONNECTION_REJECTED:
-          resultCode = LDAPResultCode.CONSTRAINT_VIOLATION;
-          break;
-        case INVALID_CREDENTIALS:
-          resultCode = LDAPResultCode.INVALID_CREDENTIALS;
-          break;
-        default:
-          resultCode = LDAPResultCode.OTHER;
-          break;
-        }
-
-        LocalizableMessage errMsg;
-        if (message == null)
-        {
-          errMsg =
-              INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION.get();
-        }
-        else
-        {
-          errMsg = message;
-        }
+        int resultCode = toResultCode(disconnectReason);
+        LocalizableMessage errMsg = message != null ? message : INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION.get();
 
         ExtendedResponseProtocolOp notificationOp =
             new ExtendedResponseProtocolOp(resultCode, errMsg, null,
@@ -1069,15 +1055,12 @@
     // NYI -- Deregister the client connection from any server components that
     // might know about it.
 
-    // Log a disconnect message.
     logDisconnect(this, disconnectReason, message);
 
     try
     {
-      PluginConfigManager pluginManager =
-          DirectoryServer.getPluginConfigManager();
-      pluginManager.invokePostDisconnectPlugins(this, disconnectReason,
-          message);
+      PluginConfigManager pluginManager = DirectoryServer.getPluginConfigManager();
+      pluginManager.invokePostDisconnectPlugins(this, disconnectReason, message);
     }
     catch (Exception e)
     {
@@ -1085,6 +1068,30 @@
     }
   }
 
+  private int toResultCode(DisconnectReason disconnectReason)
+  {
+    switch (disconnectReason)
+    {
+    case PROTOCOL_ERROR:
+      return LDAPResultCode.PROTOCOL_ERROR;
+    case SERVER_SHUTDOWN:
+      return LDAPResultCode.UNAVAILABLE;
+    case SERVER_ERROR:
+      return DirectoryServer.getServerErrorResultCode().intValue();
+    case ADMIN_LIMIT_EXCEEDED:
+    case IDLE_TIME_LIMIT_EXCEEDED:
+    case MAX_REQUEST_SIZE_EXCEEDED:
+    case IO_TIMEOUT:
+      return LDAPResultCode.ADMIN_LIMIT_EXCEEDED;
+    case CONNECTION_REJECTED:
+      return LDAPResultCode.CONSTRAINT_VIOLATION;
+    case INVALID_CREDENTIALS:
+      return LDAPResultCode.INVALID_CREDENTIALS;
+    default:
+      return LDAPResultCode.OTHER;
+    }
+  }
+
   /**
    * Retrieves the set of operations in progress for this client
    * connection. This list must not be altered by any caller.
@@ -1235,27 +1242,23 @@
       CancelRequest cancelRequest)
   {
     Operation op = operationsInProgress.get(messageID);
-    if (op == null)
-    {
-      // See if the operation is in the list of persistent searches.
-      for (PersistentSearch ps : getPersistentSearches())
-      {
-        if (ps.getMessageID() == messageID)
-        {
-          // We only need to find the first persistent search
-          // associated with the provided message ID. The persistent
-          // search will ensure that all other related persistent
-          // searches are cancelled.
-          return ps.cancel();
-        }
-      }
-
-      return new CancelResult(ResultCode.NO_SUCH_OPERATION, null);
-    }
-    else
+    if (op != null)
     {
       return op.cancel(cancelRequest);
     }
+
+    // See if the operation is in the list of persistent searches.
+    for (PersistentSearch ps : getPersistentSearches())
+    {
+      if (ps.getMessageID() == messageID)
+      {
+        // We only need to find the first persistent search
+        // associated with the provided message ID. The persistent search
+        // will ensure that all other related persistent searches are cancelled.
+        return ps.cancel();
+      }
+    }
+    return new CancelResult(ResultCode.NO_SUCH_OPERATION, null);
   }
 
   /**
@@ -1535,15 +1538,13 @@
       switch (message.getProtocolOpType())
       {
       case OP_TYPE_ABANDON_REQUEST:
-        result = processAbandonRequest(message, opControls);
-        return result;
+        return processAbandonRequest(message, opControls);
       case OP_TYPE_ADD_REQUEST:
-        result = processAddRequest(message, opControls);
-        return result;
+        return processAddRequest(message, opControls);
       case OP_TYPE_BIND_REQUEST:
+        boolean isSaslBind = message.getBindRequestProtocolOp().getAuthenticationType() == AuthenticationType.SASL;
         bindInProgress.set(true);
-        if(message.getBindRequestProtocolOp().
-            getAuthenticationType() == AuthenticationType.SASL)
+        if (isSaslBind)
         {
           saslBindInProgress.set(true);
         }
@@ -1551,45 +1552,36 @@
         if(!result)
         {
           bindInProgress.set(false);
-          if(message.getBindRequestProtocolOp().
-              getAuthenticationType() == AuthenticationType.SASL)
+          if (isSaslBind)
           {
             saslBindInProgress.set(false);
           }
         }
         return result;
       case OP_TYPE_COMPARE_REQUEST:
-        result = processCompareRequest(message, opControls);
-        return result;
+        return processCompareRequest(message, opControls);
       case OP_TYPE_DELETE_REQUEST:
-        result = processDeleteRequest(message, opControls);
-        return result;
+        return processDeleteRequest(message, opControls);
       case OP_TYPE_EXTENDED_REQUEST:
-        if(message.getExtendedRequestProtocolOp().getOID().equals(
-            OID_START_TLS_REQUEST))
+        boolean isStartTlsRequest = OID_START_TLS_REQUEST.equals(message.getExtendedRequestProtocolOp().getOID());
+        if (isStartTlsRequest)
         {
           startTLSInProgress.set(true);
         }
         result = processExtendedRequest(message, opControls);
-        if(!result &&
-            message.getExtendedRequestProtocolOp().getOID().equals(
-                OID_START_TLS_REQUEST))
+        if (!result && isStartTlsRequest)
         {
           startTLSInProgress.set(false);
         }
         return result;
       case OP_TYPE_MODIFY_REQUEST:
-        result = processModifyRequest(message, opControls);
-        return result;
+        return processModifyRequest(message, opControls);
       case OP_TYPE_MODIFY_DN_REQUEST:
-        result = processModifyDNRequest(message, opControls);
-        return result;
+        return processModifyDNRequest(message, opControls);
       case OP_TYPE_SEARCH_REQUEST:
-        result = processSearchRequest(message, opControls);
-        return result;
+        return processSearchRequest(message, opControls);
       case OP_TYPE_UNBIND_REQUEST:
-        result = processUnbindRequest(message, opControls);
-        return result;
+        return processUnbindRequest(message, opControls);
       default:
         LocalizableMessage msg =
             ERR_LDAP_DISCONNECT_DUE_TO_INVALID_REQUEST_TYPE.get(message
@@ -1626,11 +1618,9 @@
    */
   private boolean processAbandonRequest(LDAPMessage message, List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
-      // LDAPv2 clients aren't allowed to send controls.
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-              ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      disconnectControlsNotAllowed();
       return false;
     }
 
@@ -1672,16 +1662,14 @@
    */
   private boolean processAddRequest(LDAPMessage message, List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
       // LDAPv2 clients aren't allowed to send controls.
       AddResponseProtocolOp responseOp =
           new AddResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
               ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-          responseOp));
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(message, responseOp);
+      disconnectControlsNotAllowed();
       return false;
     }
 
@@ -1712,6 +1700,16 @@
     return connectionValid;
   }
 
+  private void sendLDAPMessage(LDAPMessage message, ProtocolOp responseOp)
+  {
+    sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp));
+  }
+
+  private void disconnectControlsNotAllowed()
+  {
+    disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+  }
+
   /**
    * Processes the provided LDAP message as a bind request.
    *
@@ -1752,16 +1750,14 @@
         return false;
       }
 
-      if (controls != null && !controls.isEmpty())
+      if (!controls.isEmpty())
       {
         // LDAPv2 clients aren't allowed to send controls.
         BindResponseProtocolOp responseOp =
             new BindResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
                 ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-        sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-            responseOp));
-        disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-            ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+        sendLDAPMessage(message, responseOp);
+        disconnectControlsNotAllowed();
         return false;
       }
 
@@ -1857,16 +1853,14 @@
    */
   private boolean processCompareRequest(LDAPMessage message, List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
       // LDAPv2 clients aren't allowed to send controls.
       CompareResponseProtocolOp responseOp =
           new CompareResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
               ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-          responseOp));
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(message, responseOp);
+      disconnectControlsNotAllowed();
       return false;
     }
 
@@ -1913,16 +1907,14 @@
    */
   private boolean processDeleteRequest(LDAPMessage message, List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
       // LDAPv2 clients aren't allowed to send controls.
       DeleteResponseProtocolOp responseOp =
           new DeleteResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
               ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-          responseOp));
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(message, responseOp);
+      disconnectControlsNotAllowed();
       return false;
     }
 
@@ -2031,16 +2023,14 @@
    */
   private boolean processModifyRequest(LDAPMessage message, List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
       // LDAPv2 clients aren't allowed to send controls.
       ModifyResponseProtocolOp responseOp =
           new ModifyResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
               ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-          responseOp));
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(message, responseOp);
+      disconnectControlsNotAllowed();
       return false;
     }
 
@@ -2088,16 +2078,14 @@
    */
   private boolean processModifyDNRequest(LDAPMessage message, List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
       // LDAPv2 clients aren't allowed to send controls.
       ModifyDNResponseProtocolOp responseOp =
           new ModifyDNResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
               ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-          responseOp));
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(message, responseOp);
+      disconnectControlsNotAllowed();
       return false;
     }
 
@@ -2145,16 +2133,14 @@
   private boolean processSearchRequest(LDAPMessage message,
       List<Control> controls)
   {
-    if (ldapVersion == 2 && controls != null && !controls.isEmpty())
+    if (ldapVersion == 2 && !controls.isEmpty())
     {
       // LDAPv2 clients aren't allowed to send controls.
       SearchResultDoneProtocolOp responseOp =
           new SearchResultDoneProtocolOp(LDAPResultCode.PROTOCOL_ERROR,
               ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
-      sendLDAPMessage(new LDAPMessage(message.getMessageID(),
-          responseOp));
-      disconnect(DisconnectReason.PROTOCOL_ERROR, false,
-          ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get());
+      sendLDAPMessage(message, responseOp);
+      disconnectControlsNotAllowed();
       return false;
     }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPAuthenticationHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPAuthenticationHandler.java
index c366e7c..1657009 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPAuthenticationHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPAuthenticationHandler.java
@@ -16,6 +16,13 @@
  */
 package org.opends.server.tools;
 
+import static com.forgerock.opendj.cli.ArgumentConstants.*;
+
+import static org.opends.messages.ToolMessages.*;
+import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -31,6 +38,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.StringTokenizer;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -44,11 +52,10 @@
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslClient;
 
-import com.forgerock.opendj.cli.ClientException;
-import com.forgerock.opendj.cli.ConsoleApplication;
-import com.forgerock.opendj.cli.ReturnCode;
-
 import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.LocalizableMessageDescriptor.Arg0;
+import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
+import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
@@ -61,12 +68,9 @@
 import org.opends.server.types.LDAPException;
 import org.opends.server.util.Base64;
 
-import static com.forgerock.opendj.cli.ArgumentConstants.*;
-
-import static org.opends.messages.ToolMessages.*;
-import static org.opends.server.protocols.ldap.LDAPConstants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
+import com.forgerock.opendj.cli.ClientException;
+import com.forgerock.opendj.cli.ConsoleApplication;
+import com.forgerock.opendj.cli.ReturnCode;
 
 /**
  * This class provides a generic interface that LDAP clients can use to perform
@@ -88,42 +92,32 @@
 public class LDAPAuthenticationHandler
        implements PrivilegedExceptionAction<Object>, CallbackHandler
 {
-  /** The bind DN for GSSAPI authentication. */
-  private ByteSequence gssapiBindDN;
-
   /** The LDAP reader that will be used to read data from the server. */
   private final LDAPReader reader;
-
   /** The LDAP writer that will be used to send data to the server. */
   private final LDAPWriter writer;
 
-  /**
-   * The atomic integer that will be used to obtain message IDs for request
-   * messages.
-   */
+  /** The atomic integer that will be used to obtain message IDs for request messages. */
   private final AtomicInteger nextMessageID;
 
   /** An array filled with the inner pad byte. */
   private byte[] iPad;
-
   /** An array filled with the outer pad byte. */
   private byte[] oPad;
 
-  /** The authentication password for GSSAPI authentication. */
-  private char[] gssapiAuthPW;
-
   /** The message digest that will be used to create MD5 hashes. */
   private MessageDigest md5Digest;
-
   /** The secure random number generator for use by this authentication handler. */
   private SecureRandom secureRandom;
 
+  /** The bind DN for GSSAPI authentication. */
+  private ByteSequence gssapiBindDN;
   /** The authentication ID for GSSAPI authentication. */
   private String gssapiAuthID;
-
   /** The authorization ID for GSSAPI authentication. */
   private String gssapiAuthzID;
-
+  /** The authentication password for GSSAPI authentication. */
+  private char[] gssapiAuthPW;
   /** The quality of protection for GSSAPI authentication. */
   private String gssapiQoP;
 
@@ -200,36 +194,23 @@
    *          specified SASL mechanism, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String,LocalizableMessage> getSASLProperties(
-          String mechanism)
+  public static Map<String, LocalizableMessage> getSASLProperties(String mechanism)
   {
-    String upperName = toUpperCase(mechanism);
-    if (upperName.equals(SASL_MECHANISM_ANONYMOUS))
+    switch (toUpperCase(mechanism))
     {
+    case SASL_MECHANISM_ANONYMOUS:
       return getSASLAnonymousProperties();
-    }
-    else if (upperName.equals(SASL_MECHANISM_CRAM_MD5))
-    {
+    case SASL_MECHANISM_CRAM_MD5:
       return getSASLCRAMMD5Properties();
-    }
-    else if (upperName.equals(SASL_MECHANISM_DIGEST_MD5))
-    {
+    case SASL_MECHANISM_DIGEST_MD5:
       return getSASLDigestMD5Properties();
-    }
-    else if (upperName.equals(SASL_MECHANISM_EXTERNAL))
-    {
+    case SASL_MECHANISM_EXTERNAL:
       return getSASLExternalProperties();
-    }
-    else if (upperName.equals(SASL_MECHANISM_GSSAPI))
-    {
+    case SASL_MECHANISM_GSSAPI:
       return getSASLGSSAPIProperties();
-    }
-    else if (upperName.equals(SASL_MECHANISM_PLAIN))
-    {
+    case SASL_MECHANISM_PLAIN:
       return getSASLPlainProperties();
-    }
-    else
-    {
+    default:
       // This is an unsupported mechanism.
       return null;
     }
@@ -279,21 +260,26 @@
         bindPassword = ByteString.empty();
     }
 
-
     // Make sure that critical elements aren't null.
     if (bindDN == null)
     {
       bindDN = ByteString.empty();
     }
 
+    sendSimpleBindRequest(ldapVersion, bindDN, bindPassword, requestControls);
 
-    // Create the bind request and send it to the server.
+    LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE);
+    responseControls.addAll(responseMessage.getControls());
+    checkConnected(responseMessage);
+    return checkSuccessfulSimpleBind(responseMessage);
+  }
+
+  private void sendSimpleBindRequest(int ldapVersion, ByteSequence bindDN, ByteSequence bindPassword,
+      List<Control> requestControls) throws ClientException
+  {
     BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN.toByteString(), ldapVersion,
-             bindPassword.toByteString());
-    LDAPMessage bindRequestMessage =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
-                         requestControls);
+        new BindRequestProtocolOp(bindDN.toByteString(), ldapVersion, bindPassword.toByteString());
+    LDAPMessage bindRequestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls);
 
     try
     {
@@ -301,87 +287,44 @@
     }
     catch (IOException ioe)
     {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
+      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(ioe));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
     }
     catch (Exception e)
     {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(e));
+      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(e));
       throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e);
     }
-
-
-    // Read the response from the server.
-    LDAPMessage responseMessage;
-    try
-    {
-      responseMessage = reader.readMessage();
-      if (responseMessage == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe));
-      throw new ClientException(
-          ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(
-          ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // See if there are any controls in the response.  If so, then add them to
-    // the response controls list.
-    List<Control> respControls = responseMessage.getControls();
-    if (respControls != null && !respControls.isEmpty())
-    {
-      responseControls.addAll(respControls);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    generateError(responseMessage);
-
-
-    BindResponseProtocolOp bindResponse =
-         responseMessage.getBindResponseProtocolOp();
-    int resultCode = bindResponse.getResultCode();
-    if (resultCode == ReturnCode.SUCCESS.get())
-    {
-      // FIXME -- Need to look for things like password expiration warning,
-      // reset notice, etc.
-      return null;
-    }
-
-    // FIXME -- Add support for referrals.
-
-    LocalizableMessage message = ERR_LDAPAUTH_SIMPLE_BIND_FAILED.get();
-    throw new LDAPException(resultCode, bindResponse.getErrorMessage(),
-                            message, bindResponse.getMatchedDN(), null);
   }
 
+  private BindResponseProtocolOp checkSuccessfulBind(LDAPMessage responseMessage, String saslMechanism)
+      throws LDAPException
+  {
+    BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp();
+    int resultCode = bindResponse.getResultCode();
+    if (resultCode != ReturnCode.SUCCESS.get())
+    {
+      // FIXME -- Add support for referrals.
+      LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(saslMechanism);
+      throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null);
+    }
+    // FIXME -- Need to look for things like password expiration warning, reset notice, etc.
+    return bindResponse;
+  }
 
+  private String checkSuccessfulSimpleBind(LDAPMessage responseMessage) throws LDAPException
+  {
+    BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp();
+    int resultCode = bindResponse.getResultCode();
+    if (resultCode != ReturnCode.SUCCESS.get())
+    {
+      // FIXME -- Add support for referrals.
+      LocalizableMessage message = ERR_LDAPAUTH_SIMPLE_BIND_FAILED.get();
+      throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null);
+    }
+    // FIXME -- Need to look for things like password expiration warning, reset notice, etc.
+    return null;
+  }
 
   /**
    * Processes a SASL bind using the provided information.  If the bind fails,
@@ -431,49 +374,29 @@
     if (mechanism == null || mechanism.length() == 0)
     {
       LocalizableMessage message = ERR_LDAPAUTH_NO_SASL_MECHANISM.get();
-      throw new ClientException(
-          ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
+      throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
     }
 
 
-    // Look at the mechanism name and call the appropriate method to process
-    // the request.
+    // Look at the mechanism name and call the appropriate method to process the request.
     saslMechanism = toUpperCase(mechanism);
-    if (saslMechanism.equals(SASL_MECHANISM_ANONYMOUS))
+    switch (saslMechanism)
     {
-      return doSASLAnonymous(bindDN, saslProperties, requestControls,
-                             responseControls);
-    }
-    else if (saslMechanism.equals(SASL_MECHANISM_CRAM_MD5))
-    {
-      return doSASLCRAMMD5(bindDN, bindPassword, saslProperties,
-                           requestControls, responseControls);
-    }
-    else if (saslMechanism.equals(SASL_MECHANISM_DIGEST_MD5))
-    {
-      return doSASLDigestMD5(bindDN, bindPassword, saslProperties,
-                             requestControls, responseControls);
-    }
-    else if (saslMechanism.equals(SASL_MECHANISM_EXTERNAL))
-    {
-      return doSASLExternal(bindDN, saslProperties, requestControls,
-                            responseControls);
-    }
-    else if (saslMechanism.equals(SASL_MECHANISM_GSSAPI))
-    {
-      return doSASLGSSAPI(bindDN, bindPassword, saslProperties, requestControls,
-                          responseControls);
-    }
-    else if (saslMechanism.equals(SASL_MECHANISM_PLAIN))
-    {
-      return doSASLPlain(bindDN, bindPassword, saslProperties, requestControls,
-                         responseControls);
-    }
-    else
-    {
+    case SASL_MECHANISM_ANONYMOUS:
+      return doSASLAnonymous(bindDN, saslProperties, requestControls, responseControls);
+    case SASL_MECHANISM_CRAM_MD5:
+      return doSASLCRAMMD5(bindDN, bindPassword, saslProperties, requestControls, responseControls);
+    case SASL_MECHANISM_DIGEST_MD5:
+      return doSASLDigestMD5(bindDN, bindPassword, saslProperties, requestControls, responseControls);
+    case SASL_MECHANISM_EXTERNAL:
+      return doSASLExternal(bindDN, saslProperties, requestControls, responseControls);
+    case SASL_MECHANISM_GSSAPI:
+      return doSASLGSSAPI(bindDN, bindPassword, saslProperties, requestControls, responseControls);
+    case SASL_MECHANISM_PLAIN:
+      return doSASLPlain(bindDN, bindPassword, saslProperties, requestControls, responseControls);
+    default:
       LocalizableMessage message = ERR_LDAPAUTH_UNSUPPORTED_SASL_MECHANISM.get(mechanism);
-      throw new ClientException(
-          ReturnCode.CLIENT_SIDE_AUTH_UNKNOWN, message);
+      throw new ClientException(ReturnCode.CLIENT_SIDE_AUTH_UNKNOWN, message);
     }
   }
 
@@ -502,7 +425,7 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLAnonymous(ByteSequence bindDN,
+  private String doSASLAnonymous(ByteSequence bindDN,
                      Map<String,List<String>> saslProperties,
                      List<Control> requestControls,
                      List<Control> responseControls)
@@ -510,151 +433,38 @@
   {
     String trace = null;
 
-
-    // Evaluate the properties provided.  The only one we'll allow is the trace
-    // property, but it is not required.
-    if (saslProperties == null || saslProperties.isEmpty())
+    // The only allowed property is the trace property, but it is not required.
+    if (saslProperties != null)
     {
-      // This is fine because there are no required properties for this mechanism.
-    }
-    else
-    {
-      for (String name : saslProperties.keySet())
+      for (Entry<String, List<String>> entry : saslProperties.entrySet())
       {
+        String name = entry.getKey();
+        List<String> values = entry.getValue();
         if (name.equalsIgnoreCase(SASL_PROPERTY_TRACE))
         {
           // This is acceptable, and we'll take any single value.
-          List<String> values = saslProperties.get(name);
-          Iterator<String> iterator = values.iterator();
-          if (iterator.hasNext())
-          {
-            trace = iterator.next();
-
-            if (iterator.hasNext())
-            {
-              LocalizableMessage message = ERR_LDAPAUTH_TRACE_SINGLE_VALUED.get();
-              throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
-            }
-          }
+          trace = getSingleValue(values, ERR_LDAPAUTH_TRACE_SINGLE_VALUED);
         }
         else
         {
           LocalizableMessage message = ERR_LDAPAUTH_INVALID_SASL_PROPERTY.get(
               name, SASL_MECHANISM_ANONYMOUS);
-          throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                    message);
+          throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
         }
       }
     }
 
-
     // Construct the bind request and send it to the server.
-    ByteString saslCredentials;
-    if (trace == null)
-    {
-      saslCredentials = null;
-    }
-    else
-    {
-      saslCredentials = ByteString.valueOfUtf8(trace);
-    }
+    ByteString saslCredentials = trace != null ? ByteString.valueOfUtf8(trace) : null;
+    sendBindRequest(SASL_MECHANISM_ANONYMOUS, bindDN, saslCredentials, requestControls);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN.toByteString(),
-             SASL_MECHANISM_ANONYMOUS, saslCredentials);
-    LDAPMessage requestMessage =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
-                         requestControls);
-
-    try
-    {
-      writer.writeMessage(requestMessage);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-          SASL_MECHANISM_ANONYMOUS, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-          SASL_MECHANISM_ANONYMOUS, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e);
-    }
-
-
-    // Read the response from the server.
-    LDAPMessage responseMessage;
-    try
-    {
-      responseMessage = reader.readMessage();
-      if (responseMessage == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // See if there are any controls in the response.  If so, then add them to
-    // the response controls list.
-    List<Control> respControls = responseMessage.getControls();
-    if (respControls != null && ! respControls.isEmpty())
-    {
-      responseControls.addAll(respControls);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    generateError(responseMessage);
-
-
-    BindResponseProtocolOp bindResponse =
-         responseMessage.getBindResponseProtocolOp();
-    int resultCode = bindResponse.getResultCode();
-    if (resultCode == ReturnCode.SUCCESS.get())
-    {
-      // FIXME -- Need to look for things like password expiration warning,
-      // reset notice, etc.
-      return null;
-    }
-
-    // FIXME -- Add support for referrals.
-
-    LocalizableMessage message =
-        ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_ANONYMOUS);
-    throw new LDAPException(resultCode, bindResponse.getErrorMessage(),
-                            message, bindResponse.getMatchedDN(), null);
+    LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE);
+    responseControls.addAll(responseMessage.getControls());
+    checkConnected(responseMessage);
+    checkSuccessfulBind(responseMessage, SASL_MECHANISM_ANONYMOUS);
+    return null;
   }
 
-
-
   /**
    * Retrieves the set of properties that a client may provide when performing a
    * SASL ANONYMOUS bind, mapped from the property names to their corresponding
@@ -664,7 +474,7 @@
    *          SASL ANONYMOUS bind, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String, LocalizableMessage> getSASLAnonymousProperties()
+  private static LinkedHashMap<String, LocalizableMessage> getSASLAnonymousProperties()
   {
     LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(1);
 
@@ -701,7 +511,7 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLCRAMMD5(ByteSequence bindDN,
+  private String doSASLCRAMMD5(ByteSequence bindDN,
                      ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
                      List<Control> requestControls,
@@ -721,20 +531,21 @@
               ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
     }
 
-    for (String name : saslProperties.keySet())
+    for (Entry<String, List<String>> entry : saslProperties.entrySet())
     {
+      String name = entry.getKey();
+      List<String> values = entry.getValue();
       String lowerName = toLowerCase(name);
 
       if (lowerName.equals(SASL_PROPERTY_AUTHID))
       {
-        authID = getAuthID(saslProperties, authID, name);
+        authID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED);
       }
       else
       {
         LocalizableMessage message = ERR_LDAPAUTH_INVALID_SASL_PROPERTY.get(
             name, SASL_MECHANISM_CRAM_MD5);
-        throw new ClientException(
-                ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
+        throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
       }
     }
 
@@ -755,108 +566,13 @@
         bindPassword = ByteString.empty();
     }
 
+    sendInitialBindRequest(SASL_MECHANISM_CRAM_MD5, bindDN);
 
-    // Construct the initial bind request to send to the server.  In this case,
-    // we'll simply indicate that we want to use CRAM-MD5 so the server will
-    // send us the challenge.
-    BindRequestProtocolOp bindRequest1 =
-         new BindRequestProtocolOp(bindDN.toByteString(),
-             SASL_MECHANISM_CRAM_MD5, null);
-    // FIXME -- Should we include request controls in both stages or just the
-    // second stage?
-    LDAPMessage requestMessage1 =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest1);
+    LDAPMessage responseMessage1 =
+        readBindResponse(ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE, SASL_MECHANISM_CRAM_MD5);
+    checkConnected(responseMessage1);
 
-    try
-    {
-      writer.writeMessage(requestMessage1);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e);
-    }
-
-
-    // Read the response from the server.
-    LDAPMessage responseMessage1;
-    try
-    {
-      responseMessage1 = reader.readMessage();
-      if (responseMessage1 == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get(
-              SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    switch (responseMessage1.getProtocolOpType())
-    {
-      case OP_TYPE_BIND_RESPONSE:
-        // We'll deal with this later.
-        break;
-
-      case OP_TYPE_EXTENDED_RESPONSE:
-        ExtendedResponseProtocolOp extendedResponse =
-             responseMessage1.getExtendedResponseProtocolOp();
-        String responseOID = extendedResponse.getOID();
-        if (responseOID != null &&
-            responseOID.equals(OID_NOTICE_OF_DISCONNECTION))
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT.
-              get(extendedResponse.getResultCode(),
-                  extendedResponse.getErrorMessage());
-          throw new LDAPException(extendedResponse.getResultCode(), message);
-        }
-        else
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse);
-          throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-        }
-
-      default:
-        LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage1.getProtocolOp());
-        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-    }
-
-
-    // Make sure that the bind response has the "SASL bind in progress" result
-    // code.
+    // Make sure that the bind response has the "SASL bind in progress" result code.
     BindResponseProtocolOp bindResponse1 =
          responseMessage1.getBindResponseProtocolOp();
     int resultCode1 = bindResponse1.getResultCode();
@@ -885,158 +601,76 @@
       throw new LDAPException(ReturnCode.PROTOCOL_ERROR.get(), message);
     }
 
+    // Use the provided password and credentials to generate the CRAM-MD5 response.
+    String salsCredentials = authID + ' ' + generateCRAMMD5Digest(bindPassword, serverChallenge);
+    sendSecondBindRequest(SASL_MECHANISM_CRAM_MD5, bindDN, salsCredentials, requestControls);
 
-    // Use the provided password and credentials to generate the CRAM-MD5
-    // response.
-    StringBuilder buffer = new StringBuilder();
-    buffer.append(authID);
-    buffer.append(' ');
-    buffer.append(generateCRAMMD5Digest(bindPassword, serverChallenge));
+    LDAPMessage responseMessage2 =
+        readBindResponse(ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE, SASL_MECHANISM_CRAM_MD5);
+    responseControls.addAll(responseMessage2.getControls());
+    checkConnected(responseMessage2);
+    checkSuccessfulBind(responseMessage2, SASL_MECHANISM_CRAM_MD5);
+    return null;
+  }
 
-
-    // Create and send the second bind request to the server.
-    BindRequestProtocolOp bindRequest2 =
-         new BindRequestProtocolOp(bindDN.toByteString(),
-             SASL_MECHANISM_CRAM_MD5, ByteString.valueOfUtf8(buffer.toString()));
-    LDAPMessage requestMessage2 =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2,
-                         requestControls);
+  /**
+   * Construct the initial bind request to send to the server. We'll simply indicate the SASL
+   * mechanism we want to use so the server will send us the challenge.
+   */
+  private void sendInitialBindRequest(String saslMechanism, ByteSequence bindDN) throws ClientException
+  {
+    // FIXME -- Should we include request controls in both stages or just the second stage?
+    BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), saslMechanism, null);
+    LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest);
 
     try
     {
-      writer.writeMessage(requestMessage2);
+      writer.writeMessage(requestMessage);
     }
     catch (IOException ioe)
     {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
+      LocalizableMessage message =
+          ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(saslMechanism, getExceptionMessage(ioe));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
     }
     catch (Exception e)
     {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
+      LocalizableMessage message =
+          ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(saslMechanism, getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e);
     }
+  }
 
-
-    // Read the response from the server.
-    LDAPMessage responseMessage2;
+  private LDAPMessage readBindResponse(Arg2<Object, Object> errCannotReadBindResponse, String saslMechanism)
+      throws ClientException
+  {
     try
     {
-      responseMessage2 = reader.readMessage();
-      if (responseMessage2 == null)
+      LDAPMessage responseMessage = reader.readMessage();
+      if (responseMessage != null)
       {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
+        return responseMessage;
       }
+      LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message);
     }
     catch (DecodeException | LDAPException e)
     {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get(
-              SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e));
+      LocalizableMessage message = errCannotReadBindResponse.get(saslMechanism, getExceptionMessage(e));
       throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
     }
     catch (IOException ioe)
     {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
+      LocalizableMessage message = errCannotReadBindResponse.get(saslMechanism, getExceptionMessage(ioe));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
     }
     catch (Exception e)
     {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get(
-          SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
+      LocalizableMessage message = errCannotReadBindResponse.get(saslMechanism, getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
     }
-
-
-    // See if there are any controls in the response.  If so, then add them to
-    // the response controls list.
-    List<Control> respControls = responseMessage2.getControls();
-    if (respControls != null && ! respControls.isEmpty())
-    {
-      responseControls.addAll(respControls);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    switch (responseMessage2.getProtocolOpType())
-    {
-      case OP_TYPE_BIND_RESPONSE:
-        // We'll deal with this later.
-        break;
-
-      case OP_TYPE_EXTENDED_RESPONSE:
-        ExtendedResponseProtocolOp extendedResponse =
-             responseMessage2.getExtendedResponseProtocolOp();
-        String responseOID = extendedResponse.getOID();
-        if (responseOID != null &&
-            responseOID.equals(OID_NOTICE_OF_DISCONNECTION))
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT.
-              get(extendedResponse.getResultCode(),
-                  extendedResponse.getErrorMessage());
-          throw new LDAPException(extendedResponse.getResultCode(), message);
-        }
-        else
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse);
-          throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-        }
-
-      default:
-        LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage2.getProtocolOp());
-        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-    }
-
-
-    BindResponseProtocolOp bindResponse2 =
-         responseMessage2.getBindResponseProtocolOp();
-    int resultCode2 = bindResponse2.getResultCode();
-    if (resultCode2 == ReturnCode.SUCCESS.get())
-    {
-      // FIXME -- Need to look for things like password expiration warning,
-      // reset notice, etc.
-      return null;
-    }
-
-    // FIXME -- Add support for referrals.
-
-    LocalizableMessage message =
-        ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_CRAM_MD5);
-    throw new LDAPException(resultCode2, bindResponse2.getErrorMessage(),
-                            message, bindResponse2.getMatchedDN(), null);
   }
 
-  private String getAuthID(Map<String, List<String>> saslProperties, String authID, String name) throws ClientException
-  {
-    List<String> values = saslProperties.get(name);
-    Iterator<String> iterator = values.iterator();
-    if (iterator.hasNext())
-    {
-      authID = iterator.next();
-
-      if (iterator.hasNext())
-      {
-        LocalizableMessage message = ERR_LDAPAUTH_AUTHID_SINGLE_VALUED.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
-      }
-    }
-    return authID;
-  }
-
-
-
   /**
    * Generates the appropriate HMAC-MD5 digest for a CRAM-MD5 authentication
    * with the given information.
@@ -1141,7 +775,7 @@
    *          SASL CRAM-MD5 bind, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String,LocalizableMessage> getSASLCRAMMD5Properties()
+  private static LinkedHashMap<String, LocalizableMessage> getSASLCRAMMD5Properties()
   {
     LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(1);
 
@@ -1178,7 +812,7 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLDigestMD5(ByteSequence bindDN,
+  private String doSASLDigestMD5(ByteSequence bindDN,
                      ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
                      List<Control> requestControls,
@@ -1202,17 +836,18 @@
       throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
     }
 
-    for (String name : saslProperties.keySet())
+    for (Entry<String, List<String>> entry : saslProperties.entrySet())
     {
+      String name = entry.getKey();
+      List<String> values = entry.getValue();
       String lowerName = toLowerCase(name);
 
       if (lowerName.equals(SASL_PROPERTY_AUTHID))
       {
-        authID = getAuthID(saslProperties, authID, name);
+        authID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED);
       }
       else if (lowerName.equals(SASL_PROPERTY_REALM))
       {
-        List<String> values = saslProperties.get(name);
         Iterator<String> iterator = values.iterator();
         if (iterator.hasNext())
         {
@@ -1229,7 +864,6 @@
       }
       else if (lowerName.equals(SASL_PROPERTY_QOP))
       {
-        List<String> values = saslProperties.get(name);
         Iterator<String> iterator = values.iterator();
         if (iterator.hasNext())
         {
@@ -1264,42 +898,17 @@
       }
       else if (lowerName.equals(SASL_PROPERTY_DIGEST_URI))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          digestURI = toLowerCase(iterator.next());
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_DIGEST_URI_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                      message);
-          }
-        }
+        digestURI = toLowerCase(getSingleValue(values, ERR_LDAPAUTH_DIGEST_URI_SINGLE_VALUED));
       }
       else if (lowerName.equals(SASL_PROPERTY_AUTHZID))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          authzID = toLowerCase(iterator.next());
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                      message);
-          }
-        }
+        authzID = toLowerCase(getSingleValue(values, ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED));
       }
       else
       {
         LocalizableMessage message = ERR_LDAPAUTH_INVALID_SASL_PROPERTY.get(
             name, SASL_MECHANISM_DIGEST_MD5);
-        throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                message);
+        throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
       }
     }
 
@@ -1321,108 +930,13 @@
     }
 
 
-    // Construct the initial bind request to send to the server.  In this case,
-    // we'll simply indicate that we want to use DIGEST-MD5 so the server will
-    // send us the challenge.
-    BindRequestProtocolOp bindRequest1 =
-         new BindRequestProtocolOp(bindDN.toByteString(),
-             SASL_MECHANISM_DIGEST_MD5, null);
-    // FIXME -- Should we include request controls in both stages or just the
-    // second stage?
-    LDAPMessage requestMessage1 =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest1);
+    sendInitialBindRequest(SASL_MECHANISM_DIGEST_MD5, bindDN);
 
-    try
-    {
-      writer.writeMessage(requestMessage1);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR,
-                                message, e);
-    }
+    LDAPMessage responseMessage1 =
+        readBindResponse(ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE, SASL_MECHANISM_DIGEST_MD5);
+    checkConnected(responseMessage1);
 
-
-    // Read the response from the server.
-    LDAPMessage responseMessage1;
-    try
-    {
-      responseMessage1 = reader.readMessage();
-      if (responseMessage1 == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get(
-              SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    switch (responseMessage1.getProtocolOpType())
-    {
-      case OP_TYPE_BIND_RESPONSE:
-        // We'll deal with this later.
-        break;
-
-      case OP_TYPE_EXTENDED_RESPONSE:
-        ExtendedResponseProtocolOp extendedResponse =
-             responseMessage1.getExtendedResponseProtocolOp();
-        String responseOID = extendedResponse.getOID();
-        if (responseOID != null &&
-            responseOID.equals(OID_NOTICE_OF_DISCONNECTION))
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT.
-              get(extendedResponse.getResultCode(),
-                  extendedResponse.getErrorMessage());
-          throw new LDAPException(extendedResponse.getResultCode(), message);
-        }
-        else
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse);
-          throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-        }
-
-      default:
-        LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage1.getProtocolOp());
-        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-    }
-
-
-    // Make sure that the bind response has the "SASL bind in progress" result
-    // code.
+    // Make sure that the bind response has the "SASL bind in progress" result code.
     BindResponseProtocolOp bindResponse1 =
          responseMessage1.getBindResponseProtocolOp();
     int resultCode1 = bindResponse1.getResultCode();
@@ -1591,163 +1105,33 @@
 
     // Generate the SASL credentials for the second bind request.
     StringBuilder credBuffer = new StringBuilder();
-    credBuffer.append("username=\"");
-    credBuffer.append(authID);
-    credBuffer.append("\"");
-
+    credBuffer.append("username=\"").append(authID).append("\"");
     if (realm != null)
     {
-      credBuffer.append(",realm=\"");
-      credBuffer.append(realm);
-      credBuffer.append("\"");
+      credBuffer.append(",realm=\"").append(realm).append("\"");
     }
-
-    credBuffer.append(",nonce=\"");
-    credBuffer.append(nonce);
-    credBuffer.append("\",cnonce=\"");
-    credBuffer.append(cnonce);
-    credBuffer.append("\",nc=");
-    credBuffer.append(nonceCount);
-    credBuffer.append(",qop=");
-    credBuffer.append(qop);
-    credBuffer.append(",digest-uri=\"");
-    credBuffer.append(digestURI);
-    credBuffer.append("\",response=");
-    credBuffer.append(responseDigest);
-
+    credBuffer.append(",nonce=\"").append(nonce);
+    credBuffer.append("\",cnonce=\"").append(cnonce);
+    credBuffer.append("\",nc=").append(nonceCount);
+    credBuffer.append(",qop=").append(qop);
+    credBuffer.append(",digest-uri=\"").append(digestURI);
+    credBuffer.append("\",response=").append(responseDigest);
     if (useUTF8)
     {
       credBuffer.append(",charset=utf-8");
     }
-
     if (authzID != null)
     {
-      credBuffer.append(",authzid=\"");
-      credBuffer.append(authzID);
-      credBuffer.append("\"");
+      credBuffer.append(",authzid=\"").append(authzID).append("\"");
     }
 
+    sendSecondBindRequest(SASL_MECHANISM_DIGEST_MD5, bindDN, credBuffer.toString(), requestControls);
 
-    // Generate and send the second bind request.
-    BindRequestProtocolOp bindRequest2 =
-         new BindRequestProtocolOp(bindDN.toByteString(),
-             SASL_MECHANISM_DIGEST_MD5,
-             ByteString.valueOfUtf8(credBuffer.toString()));
-    LDAPMessage requestMessage2 =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2,
-                         requestControls);
-
-    try
-    {
-      writer.writeMessage(requestMessage2);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR,
-                                message, e);
-    }
-
-
-    // Read the response from the server.
-    LDAPMessage responseMessage2;
-    try
-    {
-      responseMessage2 = reader.readMessage();
-      if (responseMessage2 == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get(
-              SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get(
-          SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // See if there are any controls in the response.  If so, then add them to
-    // the response controls list.
-    List<Control> respControls = responseMessage2.getControls();
-    if (respControls != null && ! respControls.isEmpty())
-    {
-      responseControls.addAll(respControls);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    switch (responseMessage2.getProtocolOpType())
-    {
-      case OP_TYPE_BIND_RESPONSE:
-        // We'll deal with this later.
-        break;
-
-      case OP_TYPE_EXTENDED_RESPONSE:
-        ExtendedResponseProtocolOp extendedResponse =
-             responseMessage2.getExtendedResponseProtocolOp();
-        String responseOID = extendedResponse.getOID();
-        if (responseOID != null &&
-            responseOID.equals(OID_NOTICE_OF_DISCONNECTION))
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT.
-              get(extendedResponse.getResultCode(),
-                  extendedResponse.getErrorMessage());
-          throw new LDAPException(extendedResponse.getResultCode(), message);
-        }
-        else
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse);
-          throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-        }
-
-      default:
-        LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage2.getProtocolOp());
-        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-    }
-
-
-    BindResponseProtocolOp bindResponse2 =
-         responseMessage2.getBindResponseProtocolOp();
-    int resultCode2 = bindResponse2.getResultCode();
-    if (resultCode2 != ReturnCode.SUCCESS.get())
-    {
-      // FIXME -- Add support for referrals.
-
-      LocalizableMessage message =
-          ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_DIGEST_MD5);
-      throw new LDAPException(resultCode2, bindResponse2.getErrorMessage(),
-                              message, bindResponse2.getMatchedDN(),
-                              null);
-    }
+    LDAPMessage responseMessage2 =
+        readBindResponse(ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE, SASL_MECHANISM_DIGEST_MD5);
+    responseControls.addAll(responseMessage2.getControls());
+    checkConnected(responseMessage2);
+    BindResponseProtocolOp bindResponse2 = checkSuccessfulBind(responseMessage2, SASL_MECHANISM_DIGEST_MD5);
 
 
     // Make sure that the bind response included server SASL credentials with
@@ -1802,12 +1186,34 @@
               ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
     }
 
-    // FIXME -- Need to look for things like password expiration warning,
-    // reset notice, etc.
+    // FIXME -- Need to look for things like password expiration warning, reset notice, etc.
     return null;
   }
 
+  private void sendSecondBindRequest(String saslMechanism, ByteSequence bindDN, String saslCredentials,
+      List<Control> requestControls) throws ClientException
+  {
+    // Generate and send the second bind request.
+    BindRequestProtocolOp bindRequest2 =
+        new BindRequestProtocolOp(bindDN.toByteString(), saslMechanism, ByteString.valueOfUtf8(saslCredentials));
+    LDAPMessage requestMessage2 = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2, requestControls);
 
+    try
+    {
+      writer.writeMessage(requestMessage2);
+    }
+    catch (IOException ioe)
+    {
+      LocalizableMessage message =
+          ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(saslMechanism, getExceptionMessage(ioe));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
+    }
+    catch (Exception e)
+    {
+      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(saslMechanism, getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e);
+    }
+  }
 
   /**
    * Reads the next token from the provided credentials string using the
@@ -1891,14 +1297,11 @@
       {
         // If this is a quoted string, then this comma is part of the token.
         // Otherwise, it's the end of the token.
-        if (isQuoted)
-        {
-          token.append(c);
-        }
-        else
+        if (!isQuoted)
         {
           break;
         }
+        token.append(c);
       }
       else if (c == '"')
       {
@@ -1911,23 +1314,17 @@
             // We have hit the end of the string, so this is fine.
             break;
           }
+          char c2 = credentials.charAt(pos++);
+          if (c2 == ',')
+          {
+            // We have hit the end of the token, so this is fine.
+            break;
+          }
           else
           {
-            char c2 = credentials.charAt(pos++);
-            if (c2 == ',')
-            {
-              // We have hit the end of the token, so this is fine.
-              break;
-            }
-            else
-            {
-              // We found the closing quote before the end of the token.  This
-              // is not fine.
-              LocalizableMessage message =
-                  ERR_LDAPAUTH_DIGESTMD5_INVALID_CLOSING_QUOTE_POS.get(pos-2);
-              throw new LDAPException(ReturnCode.INVALID_CREDENTIALS.get(),
-                                      message);
-            }
+            // We found the closing quote before the end of the token. This is not fine.
+            LocalizableMessage message = ERR_LDAPAUTH_DIGESTMD5_INVALID_CLOSING_QUOTE_POS.get(pos - 2);
+            throw new LDAPException(ReturnCode.INVALID_CREDENTIALS.get(), message);
           }
         }
         else
@@ -2028,21 +1425,14 @@
       }
     }
 
-
     // Get a hash of "username:realm:password".
-    StringBuilder a1String1 = new StringBuilder();
-    a1String1.append(authID);
-    a1String1.append(':');
-    a1String1.append((realm == null) ? "" : realm);
-    a1String1.append(':');
-
-    byte[] a1Bytes1a = a1String1.toString().getBytes(charset);
+    String a1String1 = authID + ':' + ((realm == null) ? "" : realm) + ':';
+    byte[] a1Bytes1a = a1String1.getBytes(charset);
     byte[] a1Bytes1  = new byte[a1Bytes1a.length + password.length()];
     System.arraycopy(a1Bytes1a, 0, a1Bytes1, 0, a1Bytes1a.length);
     password.copyTo(a1Bytes1, a1Bytes1a.length);
     byte[] urpHash = md5Digest.digest(a1Bytes1);
 
-
     // Next, get a hash of "urpHash:nonce:cnonce[:authzid]".
     StringBuilder a1String2 = new StringBuilder();
     a1String2.append(':');
@@ -2060,37 +1450,20 @@
     System.arraycopy(a1Bytes2a, 0, a1Bytes2, urpHash.length, a1Bytes2a.length);
     byte[] a1Hash = md5Digest.digest(a1Bytes2);
 
-
     // Next, get a hash of "AUTHENTICATE:digesturi".
     byte[] a2Bytes = ("AUTHENTICATE:" + digestURI).getBytes(charset);
     byte[] a2Hash  = md5Digest.digest(a2Bytes);
 
-
     // Get hex string representations of the last two hashes.
     String a1HashHex = getHexString(a1Hash);
     String a2HashHex = getHexString(a2Hash);
 
-
     // Put together the final string to hash, consisting of
     // "a1HashHex:nonce:nonceCount:cnonce:qop:a2HashHex" and get its digest.
-    StringBuilder kdStr = new StringBuilder();
-    kdStr.append(a1HashHex);
-    kdStr.append(':');
-    kdStr.append(nonce);
-    kdStr.append(':');
-    kdStr.append(nonceCount);
-    kdStr.append(':');
-    kdStr.append(cnonce);
-    kdStr.append(':');
-    kdStr.append(qop);
-    kdStr.append(':');
-    kdStr.append(a2HashHex);
-
-    return getHexString(md5Digest.digest(kdStr.toString().getBytes(charset)));
+    String kdStr = a1HashHex + ':' + nonce + ':' + nonceCount + ':' + cnonce + ':' + qop + ':' + a2HashHex;
+    return getHexString(md5Digest.digest(kdStr.getBytes(charset)));
   }
 
-
-
   /**
    * Generates the appropriate DIGEST-MD5 rspauth digest using the provided
    * information.
@@ -2118,7 +1491,7 @@
    * @throws  UnsupportedEncodingException  If the specified character set is
    *                                        invalid for some reason.
    */
-  public byte[] generateDigestMD5RspAuth(String authID, String authzID,
+  private byte[] generateDigestMD5RspAuth(String authID, String authzID,
                                          ByteSequence password, String realm,
                                          String nonce, String cnonce,
                                          String nonceCount, String digestURI,
@@ -2126,13 +1499,9 @@
          throws UnsupportedEncodingException
   {
     // First, get a hash of "username:realm:password".
-    StringBuilder a1String1 = new StringBuilder();
-    a1String1.append(authID);
-    a1String1.append(':');
-    a1String1.append(realm);
-    a1String1.append(':');
+    String a1String1 = authID + ':' + realm + ':';
 
-    byte[] a1Bytes1a = a1String1.toString().getBytes(charset);
+    byte[] a1Bytes1a = a1String1.getBytes(charset);
     byte[] a1Bytes1  = new byte[a1Bytes1a.length + password.length()];
     System.arraycopy(a1Bytes1a, 0, a1Bytes1, 0, a1Bytes1a.length);
     password.copyTo(a1Bytes1, a1Bytes1a.length);
@@ -2172,26 +1541,12 @@
     String a1HashHex = getHexString(a1Hash);
     String a2HashHex = getHexString(a2Hash);
 
-
     // Put together the final string to hash, consisting of
     // "a1HashHex:nonce:nonceCount:cnonce:qop:a2HashHex" and get its digest.
-    StringBuilder kdStr = new StringBuilder();
-    kdStr.append(a1HashHex);
-    kdStr.append(':');
-    kdStr.append(nonce);
-    kdStr.append(':');
-    kdStr.append(nonceCount);
-    kdStr.append(':');
-    kdStr.append(cnonce);
-    kdStr.append(':');
-    kdStr.append(qop);
-    kdStr.append(':');
-    kdStr.append(a2HashHex);
-    return md5Digest.digest(kdStr.toString().getBytes(charset));
+    String kdStr = a1HashHex + ':' + nonce + ':' + nonceCount + ':' + cnonce + ':' + qop + ':' + a2HashHex;
+    return md5Digest.digest(kdStr.getBytes(charset));
   }
 
-
-
   /**
    * Retrieves a hexadecimal string representation of the contents of the
    * provided byte array.
@@ -2224,7 +1579,7 @@
    *          SASL DIGEST-MD5 bind, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String,LocalizableMessage> getSASLDigestMD5Properties()
+  private static LinkedHashMap<String, LocalizableMessage> getSASLDigestMD5Properties()
   {
     LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(5);
 
@@ -2285,111 +1640,11 @@
     }
 
 
-    // Construct the bind request and send it to the server.
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN.toByteString(),
-             SASL_MECHANISM_EXTERNAL, null);
-    LDAPMessage requestMessage =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
-                         requestControls);
+    sendBindRequest(SASL_MECHANISM_EXTERNAL, bindDN, null, requestControls);
 
-    try
-    {
-      writer.writeMessage(requestMessage);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-          SASL_MECHANISM_EXTERNAL, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-          SASL_MECHANISM_EXTERNAL, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR,
-                                message, e);
-    }
-
-
-    // Read the response from the server.
-    LDAPMessage responseMessage;
-    try
-    {
-      responseMessage = reader.readMessage();
-      if (responseMessage == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // See if there are any controls in the response.  If so, then add them to
-    // the response controls list.
-    List<Control> respControls = responseMessage.getControls();
-    if (respControls != null && ! respControls.isEmpty())
-    {
-      responseControls.addAll(respControls);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    switch (responseMessage.getProtocolOpType())
-    {
-      case OP_TYPE_BIND_RESPONSE:
-        // We'll deal with this later.
-        break;
-
-      case OP_TYPE_EXTENDED_RESPONSE:
-        ExtendedResponseProtocolOp extendedResponse =
-             responseMessage.getExtendedResponseProtocolOp();
-        String responseOID = extendedResponse.getOID();
-        if (responseOID != null &&
-            responseOID.equals(OID_NOTICE_OF_DISCONNECTION))
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT.
-              get(extendedResponse.getResultCode(),
-                  extendedResponse.getErrorMessage());
-          throw new LDAPException(extendedResponse.getResultCode(), message);
-        }
-        else
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse);
-          throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-        }
-
-      default:
-        LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage.getProtocolOp());
-        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
-    }
-
+    LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE);
+    responseControls.addAll(responseMessage.getControls());
+    checkConnected(responseMessage);
 
     BindResponseProtocolOp bindResponse =
          responseMessage.getBindResponseProtocolOp();
@@ -2409,7 +1664,57 @@
                             message, bindResponse.getMatchedDN(), null);
   }
 
+  private void sendBindRequest(String saslMechanism, ByteSequence bindDN, ByteString saslCredentials,
+      List<Control> requestControls) throws ClientException
+  {
+    BindRequestProtocolOp bindRequest =
+        new BindRequestProtocolOp(bindDN.toByteString(), saslMechanism, saslCredentials);
+    LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls);
 
+    try
+    {
+      writer.writeMessage(requestMessage);
+    }
+    catch (IOException ioe)
+    {
+      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(saslMechanism, getExceptionMessage(ioe));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
+    }
+    catch (Exception e)
+    {
+      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(saslMechanism, getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e);
+    }
+  }
+
+  private LDAPMessage readBindResponse(Arg1<Object> errCannotReadBindResponse) throws ClientException
+  {
+    try
+    {
+      LDAPMessage responseMessage = reader.readMessage();
+      if (responseMessage != null)
+      {
+        return responseMessage;
+      }
+      LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message);
+    }
+    catch (DecodeException | LDAPException e)
+    {
+      LocalizableMessage message = errCannotReadBindResponse.get(getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
+    }
+    catch (IOException ioe)
+    {
+      LocalizableMessage message = errCannotReadBindResponse.get(getExceptionMessage(ioe));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
+    }
+    catch (Exception e)
+    {
+      LocalizableMessage message = errCannotReadBindResponse.get(getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
+    }
+  }
 
   /**
    * Retrieves the set of properties that a client may provide when performing a
@@ -2420,7 +1725,7 @@
    *          SASL EXTERNAL bind, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String,LocalizableMessage> getSASLExternalProperties()
+  private static LinkedHashMap<String, LocalizableMessage> getSASLExternalProperties()
   {
     // There are no properties for the SASL EXTERNAL mechanism.
     return new LinkedHashMap<>(0);
@@ -2455,7 +1760,7 @@
    * @throws  LDAPException  If the bind fails or some other server-side problem
    *                         occurs during processing.
    */
-  public String doSASLGSSAPI(ByteSequence bindDN,
+  private String doSASLGSSAPI(ByteSequence bindDN,
                      ByteSequence bindPassword,
                      Map<String,List<String>> saslProperties,
                      List<Control> requestControls,
@@ -2469,16 +1774,7 @@
     gssapiAuthID  = null;
     gssapiAuthzID = null;
     gssapiQoP     = "auth";
-
-    if (bindPassword == null)
-    {
-      gssapiAuthPW = null;
-    }
-    else
-    {
-      gssapiAuthPW = bindPassword.toString().toCharArray();
-    }
-
+    gssapiAuthPW = bindPassword != null ? bindPassword.toString().toCharArray() : null;
 
     // Evaluate the properties provided.  The authID is required.  The authzID,
     // KDC, QoP, and realm are optional.
@@ -2490,60 +1786,26 @@
               ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
     }
 
-    for (String name : saslProperties.keySet())
+    for (Entry<String, List<String>> entry : saslProperties.entrySet())
     {
+      String name = entry.getKey();
       String lowerName = toLowerCase(name);
+      List<String> values = entry.getValue();
 
       if (lowerName.equals(SASL_PROPERTY_AUTHID))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          gssapiAuthID = iterator.next();
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_AUTHID_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
-          }
-        }
+        gssapiAuthID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED);
       }
       else if (lowerName.equals(SASL_PROPERTY_AUTHZID))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          gssapiAuthzID = iterator.next();
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                      message);
-          }
-        }
+        gssapiAuthzID = getSingleValue(values, ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED);
       }
       else if (lowerName.equals(SASL_PROPERTY_KDC))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          kdc = iterator.next();
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_KDC_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                      message);
-          }
-        }
+        kdc = getSingleValue(values, ERR_LDAPAUTH_KDC_SINGLE_VALUED);
       }
       else if (lowerName.equals(SASL_PROPERTY_QOP))
       {
-        List<String> values = saslProperties.get(name);
         Iterator<String> iterator = values.iterator();
         if (iterator.hasNext())
         {
@@ -2580,19 +1842,7 @@
       }
       else if (lowerName.equals(SASL_PROPERTY_REALM))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          realm = iterator.next();
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_REALM_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                      message);
-          }
-        }
+        realm = getSingleValue(values, ERR_LDAPAUTH_REALM_SINGLE_VALUED);
       }
       else
       {
@@ -2645,20 +1895,17 @@
       File tempFile = File.createTempFile("login", "conf");
       configFileName = tempFile.getAbsolutePath();
       tempFile.deleteOnExit();
-      BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false));
+      try (BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false))) {
+        w.write(getClass().getName() + " {");
+        w.newLine();
 
-      w.write(getClass().getName() + " {");
-      w.newLine();
+        w.write("  com.sun.security.auth.module.Krb5LoginModule required " +
+            "client=TRUE useTicketCache=TRUE;");
+        w.newLine();
 
-      w.write("  com.sun.security.auth.module.Krb5LoginModule required " +
-              "client=TRUE useTicketCache=TRUE;");
-      w.newLine();
-
-      w.write("};");
-      w.newLine();
-
-      w.flush();
-      w.close();
+        w.write("};");
+        w.newLine();
+      }
     }
     catch (Exception e)
     {
@@ -2710,13 +1957,25 @@
     }
 
 
-    // FIXME --  Need to make sure we handle request and response controls
-    // properly, and also check for any possible message to send back to the
-    // client.
+    // FIXME -- Need to make sure we handle request and response controls properly,
+    // and also check for any possible message to send back to the client.
     return null;
   }
 
-
+  private String getSingleValue(List<String> values, Arg0 singleValuedErrMsg) throws ClientException
+  {
+    Iterator<String> it = values.iterator();
+    if (it.hasNext())
+    {
+      String result = it.next();
+      if (it.hasNext())
+      {
+        throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, singleValuedErrMsg.get());
+      }
+      return result;
+    }
+    return null;
+  }
 
   /**
    * Retrieves the set of properties that a client may provide when performing a
@@ -2727,7 +1986,7 @@
    *          SASL EXTERNAL bind, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String,LocalizableMessage> getSASLGSSAPIProperties()
+  private static LinkedHashMap<String, LocalizableMessage> getSASLGSSAPIProperties()
   {
     LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(4);
 
@@ -2791,29 +2050,19 @@
               ReturnCode.CLIENT_SIDE_PARAM_ERROR, message);
     }
 
-    for (String name : saslProperties.keySet())
+    for (Entry<String, List<String>> entry : saslProperties.entrySet())
     {
+      String name = entry.getKey();
+      List<String> values = entry.getValue();
       String lowerName = toLowerCase(name);
 
       if (lowerName.equals(SASL_PROPERTY_AUTHID))
       {
-        authID = getAuthID(saslProperties, authID, name);
+        authID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED);
       }
       else if (lowerName.equals(SASL_PROPERTY_AUTHZID))
       {
-        List<String> values = saslProperties.get(name);
-        Iterator<String> iterator = values.iterator();
-        if (iterator.hasNext())
-        {
-          authzID = iterator.next();
-
-          if (iterator.hasNext())
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR,
-                                      message);
-          }
-        }
+        authzID = getSingleValue(values, ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED);
       }
       else
       {
@@ -2841,116 +2090,17 @@
         bindPassword = ByteString.empty();
     }
 
-
     // Construct the bind request and send it to the server.
-    StringBuilder credBuffer = new StringBuilder();
-    if (authzID != null)
-    {
-      credBuffer.append(authzID);
-    }
-    credBuffer.append('\u0000');
-    credBuffer.append(authID);
-    credBuffer.append('\u0000');
-    credBuffer.append(bindPassword.toString());
+    String saslCredentials = (authzID != null ? authzID : "") + '\u0000' + authID + '\u0000' + bindPassword;
+    sendBindRequest(SASL_MECHANISM_PLAIN, bindDN, ByteString.valueOfUtf8(saslCredentials), requestControls);
 
-    ByteString saslCredentials =
-        ByteString.valueOfUtf8(credBuffer.toString());
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_PLAIN,
-                                saslCredentials);
-    LDAPMessage requestMessage =
-         new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest,
-                         requestControls);
-
-    try
-    {
-      writer.writeMessage(requestMessage);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-          SASL_MECHANISM_PLAIN, getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-          SASL_MECHANISM_PLAIN, getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR,
-                                message, e);
-    }
-
-
-    // Read the response from the server.
-    LDAPMessage responseMessage;
-    try
-    {
-      responseMessage = reader.readMessage();
-      if (responseMessage == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
-
-    // See if there are any controls in the response.  If so, then add them to
-    // the response controls list.
-    List<Control> respControls = responseMessage.getControls();
-    if (respControls != null && !respControls.isEmpty())
-    {
-      responseControls.addAll(respControls);
-    }
-
-
-    // Look at the protocol op from the response.  If it's a bind response, then
-    // continue.  If it's an extended response, then it could be a notice of
-    // disconnection so check for that.  Otherwise, generate an error.
-    generateError(responseMessage);
-
-
-    BindResponseProtocolOp bindResponse =
-         responseMessage.getBindResponseProtocolOp();
-    int resultCode = bindResponse.getResultCode();
-    if (resultCode == ReturnCode.SUCCESS.get())
-    {
-      // FIXME -- Need to look for things like password expiration warning,
-      // reset notice, etc.
-      return null;
-    }
-
-    // FIXME -- Add support for referrals.
-
-    LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_PLAIN);
-    throw new LDAPException(resultCode, bindResponse.getErrorMessage(),
-                            message, bindResponse.getMatchedDN(), null);
+    LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE);
+    responseControls.addAll(responseMessage.getControls());
+    checkConnected(responseMessage);
+    checkSuccessfulBind(responseMessage, SASL_MECHANISM_PLAIN);
+    return null;
   }
 
-
-
   /**
    * Retrieves the set of properties that a client may provide when performing a
    * SASL PLAIN bind, mapped from the property names to their corresponding
@@ -2960,7 +2110,7 @@
    *          SASL PLAIN bind, mapped from the property names to their
    *          corresponding descriptions.
    */
-  public static LinkedHashMap<String,LocalizableMessage> getSASLPlainProperties()
+  private static LinkedHashMap<String, LocalizableMessage> getSASLPlainProperties()
   {
     LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(2);
 
@@ -2988,8 +2138,7 @@
    *                         processing.
    */
   @Override
-  public Object run()
-         throws ClientException, LDAPException
+  public Object run() throws ClientException, LDAPException
   {
     if (saslMechanism == null)
     {
@@ -2999,290 +2148,151 @@
     }
     else if (saslMechanism.equals(SASL_MECHANISM_GSSAPI))
     {
-      // Create the property map that will be used by the internal SASL handler.
-      HashMap<String,String> saslProperties = new HashMap<>();
-      saslProperties.put(Sasl.QOP, gssapiQoP);
-      saslProperties.put(Sasl.SERVER_AUTH, "true");
-
-
-      // Create the SASL client that we will use to actually perform the
-      // authentication.
-      SaslClient saslClient;
-      try
-      {
-        saslClient =
-             Sasl.createSaslClient(new String[] { SASL_MECHANISM_GSSAPI },
-                                   gssapiAuthzID, "ldap", hostName,
-                                   saslProperties, this);
-      }
-      catch (Exception e)
-      {
-        LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_SASL_CLIENT.get(
-            getExceptionMessage(e));
-        throw new ClientException(
-                ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-      }
-
-
-      // Get the SASL credentials to include in the initial bind request.
-      ByteString saslCredentials;
-      if (saslClient.hasInitialResponse())
-      {
-        try
-        {
-          byte[] credBytes = saslClient.evaluateChallenge(new byte[0]);
-          saslCredentials = ByteString.wrap(credBytes);
-        }
-        catch (Exception e)
-        {
-          LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_INITIAL_CHALLENGE.
-              get(getExceptionMessage(e));
-          throw new ClientException(
-                  ReturnCode.CLIENT_SIDE_LOCAL_ERROR,
-                                    message, e);
-        }
-      }
-      else
-      {
-        saslCredentials = null;
-      }
-
-
-      BindRequestProtocolOp bindRequest =
-           new BindRequestProtocolOp(gssapiBindDN.toByteString(),
-               SASL_MECHANISM_GSSAPI, saslCredentials);
-      // FIXME -- Add controls here?
-      LDAPMessage requestMessage =
-           new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest);
-
-      try
-      {
-        writer.writeMessage(requestMessage);
-      }
-      catch (IOException ioe)
-      {
-        LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-            SASL_MECHANISM_GSSAPI, getExceptionMessage(ioe));
-        throw new ClientException(
-                ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-      }
-      catch (Exception e)
-      {
-        LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-            SASL_MECHANISM_GSSAPI, getExceptionMessage(e));
-        throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR,
-                                  message, e);
-      }
-
-
-      // Read the response from the server.
-      LDAPMessage responseMessage;
-      try
-      {
-        responseMessage = reader.readMessage();
-        if (responseMessage == null)
-        {
-          LocalizableMessage message =
-              ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-          throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                    message);
-        }
-      }
-      catch (DecodeException | LDAPException e)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-        throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-      }
-      catch (IOException ioe)
-      {
-        LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(
-            getExceptionMessage(ioe));
-        throw new ClientException(
-                ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-      }
-      catch (Exception e)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-        throw new ClientException(
-                ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-      }
-
-
-      // FIXME -- Handle response controls.
-
-
-      // Look at the protocol op from the response.  If it's a bind response,
-      // then continue.  If it's an extended response, then it could be a notice
-      // of disconnection so check for that.  Otherwise, generate an error.
-      generateError(responseMessage);
-
-
-      while (true)
-      {
-        BindResponseProtocolOp bindResponse =
-             responseMessage.getBindResponseProtocolOp();
-        int resultCode = bindResponse.getResultCode();
-        if (resultCode == ReturnCode.SUCCESS.get())
-        {
-          // We should be done after this, but we still need to look for and
-          // handle the server SASL credentials.
-          ByteString serverSASLCredentials =
-               bindResponse.getServerSASLCredentials();
-          if (serverSASLCredentials != null)
-          {
-            try
-            {
-              saslClient.evaluateChallenge(serverSASLCredentials.toByteArray());
-            }
-            catch (Exception e)
-            {
-              LocalizableMessage message =
-                  ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS.
-                    get(getExceptionMessage(e));
-              throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR,
-                                        message, e);
-            }
-          }
-
-
-          // Just to be sure, check that the login really is complete.
-          if (! saslClient.isComplete())
-          {
-            LocalizableMessage message =
-                ERR_LDAPAUTH_GSSAPI_UNEXPECTED_SUCCESS_RESPONSE.get();
-            throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR,
-                                      message);
-          }
-
-          break;
-        }
-        else if (resultCode == ReturnCode.SASL_BIND_IN_PROGRESS.get())
-        {
-          // Read the response and process the server SASL credentials.
-          ByteString serverSASLCredentials =
-               bindResponse.getServerSASLCredentials();
-          byte[] credBytes;
-          try
-          {
-            if (serverSASLCredentials == null)
-            {
-              credBytes = saslClient.evaluateChallenge(new byte[0]);
-            }
-            else
-            {
-              credBytes = saslClient.evaluateChallenge(
-                  serverSASLCredentials.toByteArray());
-            }
-          }
-          catch (Exception e)
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS.
-                get(getExceptionMessage(e));
-            throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR,
-                                      message, e);
-          }
-
-
-          // Send the next bind in the sequence to the server.
-          bindRequest =
-               new BindRequestProtocolOp(gssapiBindDN.toByteString(),
-                   SASL_MECHANISM_GSSAPI, ByteString.wrap(credBytes));
-          // FIXME -- Add controls here?
-          requestMessage =
-               new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest);
-
-
-          try
-          {
-            writer.writeMessage(requestMessage);
-          }
-          catch (IOException ioe)
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-                SASL_MECHANISM_GSSAPI, getExceptionMessage(ioe));
-            throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                      message, ioe);
-          }
-          catch (Exception e)
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(
-                SASL_MECHANISM_GSSAPI, getExceptionMessage(e));
-            throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR,
-                                      message, e);
-          }
-
-
-          // Read the response from the server.
-          try
-          {
-            responseMessage = reader.readMessage();
-            if (responseMessage == null)
-            {
-              LocalizableMessage message =
-                  ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-              throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                        message);
-            }
-          }
-          catch (DecodeException | LDAPException e)
-          {
-            LocalizableMessage message =
-                ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e));
-            throw new ClientException(
-                ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-          }
-          catch (IOException ioe)
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(
-                getExceptionMessage(ioe));
-            throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                      message, ioe);
-          }
-          catch (Exception e)
-          {
-            LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(
-                getExceptionMessage(e));
-            throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR,
-                                      message, e);
-          }
-
-
-          // FIXME -- Handle response controls.
-
-
-          // Look at the protocol op from the response.  If it's a bind
-          // response, then continue.  If it's an extended response, then it
-          // could be a notice of disconnection so check for that.  Otherwise,
-          // generate an error.
-          generateError(responseMessage);
-        }
-        else
-        {
-          // This is an error.
-          LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_BIND_FAILED.get();
-          throw new LDAPException(resultCode, bindResponse.getErrorMessage(),
-                                  message, bindResponse.getMatchedDN(),
-                                  null);
-        }
-      }
+      doSASLGSSAPI2();
+      return null;
     }
     else
     {
       LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RUN_INVOCATION.get(
           saslMechanism, getBacktrace());
+      throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
+    }
+  }
+
+  private void doSASLGSSAPI2() throws ClientException, LDAPException
+  {
+    // Create the property map that will be used by the internal SASL handler.
+    Map<String, String> saslProperties = new HashMap<>();
+    saslProperties.put(Sasl.QOP, gssapiQoP);
+    saslProperties.put(Sasl.SERVER_AUTH, "true");
+
+
+    // Create the SASL client that we will use to actually perform the
+    // authentication.
+    SaslClient saslClient;
+    try
+    {
+      saslClient =
+           Sasl.createSaslClient(new String[] { SASL_MECHANISM_GSSAPI },
+                                 gssapiAuthzID, "ldap", hostName,
+                                 saslProperties, this);
+    }
+    catch (Exception e)
+    {
+      LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_SASL_CLIENT.get(
+          getExceptionMessage(e));
       throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
+              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
     }
 
+    // FIXME -- Add controls here?
+    ByteString saslCredentials = getSaslCredentialsForInitialBind(saslClient);
+    sendBindRequest(SASL_MECHANISM_GSSAPI, gssapiBindDN, saslCredentials, null);
 
-    // FIXME -- Need to look for things like password expiration warning, reset
-    // notice, etc.
+    LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE);
+    // FIXME -- Handle response controls.
+    checkConnected(responseMessage);
+
+    while (true)
+    {
+      BindResponseProtocolOp bindResponse =
+           responseMessage.getBindResponseProtocolOp();
+      int resultCode = bindResponse.getResultCode();
+      if (resultCode == ReturnCode.SUCCESS.get())
+      {
+        evaluateGSSAPIChallenge(saslClient, bindResponse);
+        break;
+      }
+      else if (resultCode == ReturnCode.SASL_BIND_IN_PROGRESS.get())
+      {
+        // FIXME -- Add controls here?
+        ByteString credBytes = evaluateSaslChallenge(saslClient, bindResponse);
+        sendBindRequest(SASL_MECHANISM_GSSAPI, gssapiBindDN, credBytes, null);
+
+        responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE);
+        // FIXME -- Handle response controls.
+        checkConnected(responseMessage);
+      }
+      else
+      {
+        // This is an error.
+        LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_BIND_FAILED.get();
+        throw new LDAPException(resultCode, bindResponse.getErrorMessage(),
+                                message, bindResponse.getMatchedDN(),
+                                null);
+      }
+    }
+    // FIXME -- Need to look for things like password expiration warning, reset notice, etc.
+  }
+
+
+  private void evaluateGSSAPIChallenge(SaslClient saslClient, BindResponseProtocolOp bindResponse)
+      throws ClientException
+  {
+    // We should be done after this, but we still need to look for and
+    // handle the server SASL credentials.
+    ByteString serverSASLCredentials = bindResponse.getServerSASLCredentials();
+    if (serverSASLCredentials != null)
+    {
+      try
+      {
+        saslClient.evaluateChallenge(serverSASLCredentials.toByteArray());
+      }
+      catch (Exception e)
+      {
+        LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS.get(getExceptionMessage(e));
+        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
+      }
+    }
+
+    // Just to be sure, check that the login really is complete.
+    if (!saslClient.isComplete())
+    {
+      LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_UNEXPECTED_SUCCESS_RESPONSE.get();
+      throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message);
+    }
+  }
+
+  private ByteString evaluateSaslChallenge(SaslClient saslClient, BindResponseProtocolOp bindResponse)
+      throws ClientException
+  {
+    try
+    {
+      ByteString saslCredentials = bindResponse.getServerSASLCredentials();
+      byte[] bs = saslCredentials != null ? saslCredentials.toByteArray() : new byte[0];
+      return ByteString.wrap(saslClient.evaluateChallenge(bs));
+    }
+    catch (Exception e)
+    {
+      LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS.get(getExceptionMessage(e));
+      throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
+    }
+  }
+
+  private ByteString getSaslCredentialsForInitialBind(SaslClient saslClient) throws ClientException
+  {
+    if (saslClient.hasInitialResponse())
+    {
+      try
+      {
+        return ByteString.wrap(saslClient.evaluateChallenge(new byte[0]));
+      }
+      catch (Exception e)
+      {
+        LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_INITIAL_CHALLENGE.get(getExceptionMessage(e));
+        throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
+      }
+    }
     return null;
   }
 
-  private void generateError(LDAPMessage responseMessage) throws LDAPException, ClientException
+  /**
+   * Look at the protocol op from the response.
+   * If it's a bind response, then continue.
+   * If it's an extended response, then check it is not a notice of disconnection.
+   * Otherwise, generate an error.
+   */
+  private void checkConnected(LDAPMessage responseMessage) throws LDAPException, ClientException
   {
     switch (responseMessage.getProtocolOpType())
     {
@@ -3417,40 +2427,7 @@
     }
 
 
-    // Read the response from the server.
-    LDAPMessage responseMessage;
-    try
-    {
-      responseMessage = reader.readMessage();
-      if (responseMessage == null)
-      {
-        LocalizableMessage message =
-            ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get();
-        throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN,
-                                  message);
-      }
-    }
-    catch (DecodeException | LDAPException e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e);
-    }
-    catch (IOException ioe)
-    {
-      LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE.get(
-          getExceptionMessage(ioe));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe);
-    }
-    catch (Exception e)
-    {
-      LocalizableMessage message =
-          ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE.get(getExceptionMessage(e));
-      throw new ClientException(
-              ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e);
-    }
-
+    LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE);
 
     // If the protocol op isn't an extended response, then that's a problem.
     if (responseMessage.getProtocolOpType() != OP_TYPE_EXTENDED_RESPONSE)
@@ -3493,13 +2470,10 @@
       return null;
     }
 
-    String valueString = authzID.toString();
-    if (valueString == null || valueString.length() == 0 ||
-        valueString.equalsIgnoreCase("dn:"))
+    if (!"dn:".equalsIgnoreCase(authzID.toString()))
     {
-      return null;
+      return authzID;
     }
-
-    return authzID;
+    return null;
   }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPPasswordModify.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPPasswordModify.java
index 243f0f8..ba7e6cb 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPPasswordModify.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPPasswordModify.java
@@ -29,7 +29,6 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.forgerock.i18n.LocalizableMessage;
@@ -654,38 +653,32 @@
 
     // See if the response included any controls that we recognize, and if so
     // then handle them.
-    List<Control> responseControls = responseMessage.getControls();
-    if (responseControls != null)
+    for (Control c : responseMessage.getControls())
     {
-      for (Control c : responseControls)
+      if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
       {
-        if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
+        try
         {
-          try
-          {
-            PasswordPolicyResponseControl pwPolicyControl =
-              PasswordPolicyResponseControl.DECODER
-                .decode(c.isCritical(), ((LDAPControl) c).getValue());
+          PasswordPolicyResponseControl pwPolicyControl =
+            PasswordPolicyResponseControl.DECODER
+              .decode(c.isCritical(), ((LDAPControl) c).getValue());
 
-            PasswordPolicyWarningType pwPolicyWarningType =
-                 pwPolicyControl.getWarningType();
-            if (pwPolicyWarningType != null)
-            {
-              printWrappedText(
-                      out, INFO_LDAPPWMOD_PWPOLICY_WARNING.get(pwPolicyWarningType, pwPolicyControl.getWarningValue()));
-            }
-
-            PasswordPolicyErrorType pwPolicyErrorType =
-                 pwPolicyControl.getErrorType();
-            if (pwPolicyErrorType != null)
-            {
-              printWrappedText(out, INFO_LDAPPWMOD_PWPOLICY_ERROR.get(pwPolicyErrorType));
-            }
-          }
-          catch (Exception e)
+          PasswordPolicyWarningType pwPolicyWarningType = pwPolicyControl.getWarningType();
+          if (pwPolicyWarningType != null)
           {
-            printWrappedText(err, ERR_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL.get(e));
+            printWrappedText(
+                    out, INFO_LDAPPWMOD_PWPOLICY_WARNING.get(pwPolicyWarningType, pwPolicyControl.getWarningValue()));
           }
+
+          PasswordPolicyErrorType pwPolicyErrorType = pwPolicyControl.getErrorType();
+          if (pwPolicyErrorType != null)
+          {
+            printWrappedText(out, INFO_LDAPPWMOD_PWPOLICY_ERROR.get(pwPolicyErrorType));
+          }
+        }
+        catch (Exception e)
+        {
+          printWrappedText(err, ERR_LDAPPWMOD_CANNOT_DECODE_PWPOLICY_CONTROL.get(e));
         }
       }
     }
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
index 182814b..c257245 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
@@ -31,7 +31,6 @@
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteString;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.api.SASLMechanismHandler;
@@ -46,9 +45,7 @@
 
 import com.forgerock.opendj.cli.ClientException;
 
-/**
- * A set of test cases for the LDAP authentication handler.
- */
+/** A set of test cases for the LDAP authentication handler. */
 public class LDAPAuthenticationHandlerTestCase
        extends ToolsTestCase
 {
@@ -67,8 +64,6 @@
     getFQDN();
   }
 
-
-
   /**
    * Retrieves the names of the supported SASL mechanisms.
    *
@@ -88,8 +83,6 @@
     };
   }
 
-
-
   /**
    * Tests the <CODE>getSupportedSASLMechanisms</CODE> method.
    *
@@ -114,29 +107,16 @@
   @Test(dataProvider = "saslMechanisms")
   public void testGetSASLProperties(String saslMechanismName)
   {
-    LinkedHashMap<String, LocalizableMessage> properties =
-         LDAPAuthenticationHandler.getSASLProperties(saslMechanismName);
-
-    assertNotNull(properties);
+    assertNotNull(LDAPAuthenticationHandler.getSASLProperties(saslMechanismName));
   }
 
-
-
-  /**
-   * Tests the <CODE>getSASLProperties</CODE> method with an unsupported
-   * mechanism name.
-   */
+  /** Tests the <CODE>getSASLProperties</CODE> method with an unsupported mechanism name. */
   @Test
-  public void testGetSASLPropertiesInvlaid()
+  public void testGetSASLPropertiesInvalid()
   {
-    LinkedHashMap<String,LocalizableMessage> properties =
-         LDAPAuthenticationHandler.getSASLProperties("unsupportedMechanism");
-
-    assertNull(properties);
+    assertNull(LDAPAuthenticationHandler.getSASLProperties("unsupportedMechanism"));
   }
 
-
-
   /**
    * Tests the <CODE>doSimpleBind</CODE> method with a valid DN and password and
    * with no request controls.
@@ -147,8 +127,8 @@
   public void testDoSimpleBindWithValidDNAndPWNoControls()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     try (Socket s = newSocket())
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -157,8 +137,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSimpleBind</CODE> method with a null DN and password and
    * no request controls.
@@ -169,8 +147,8 @@
   public void testDoSimpleBindWithNullDNAndPWNoControls()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     try (Socket s = newSocket())
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -178,8 +156,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSimpleBind</CODE> method with an empty DN and password
    * and no request controls.
@@ -190,8 +166,8 @@
   public void testDoSimpleBindWithEmptyDNAndPWNoControls()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     try (Socket s = newSocket())
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -199,20 +175,18 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSimpleBind</CODE> method with an valid DN but no
    * password.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSimpleBindWithDNButNoPassword()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
 
     try (Socket s = newSocket())
     {
@@ -223,20 +197,18 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSimpleBind</CODE> method with an valid DN but an invalid
    * password.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSimpleBindWithDNButInvalidPassword()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
 
     try (Socket s = newSocket())
     {
@@ -247,8 +219,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSimpleBind</CODE> method with the password policy
    * request control.
@@ -259,8 +229,8 @@
   public void testDoSimpleBindWithPasswordPolicyControl()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     requestControls.add(new PasswordPolicyRequestControl());
     try (Socket s = newSocket())
     {
@@ -270,20 +240,18 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method with a null mechanism.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindNullMechanism()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     try (Socket s = newSocket())
     {
@@ -292,20 +260,18 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method with an empty mechanism.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindEmptyMechanism()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     try (Socket s = newSocket())
     {
@@ -314,20 +280,18 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method with an invalid mechanism.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindInvalidMechanism()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     try (Socket s = newSocket())
     {
@@ -337,19 +301,17 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS
    * authentication is disabled in the server.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindAnonymousDisabled()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("trace", newArrayList("testDoSASLBindAnonymousDisabled"));
 
     try (Socket s = newSocket())
@@ -359,8 +321,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS
    * authentication is enabled in the server.
@@ -374,7 +334,7 @@
     AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler();
     handler.initializeSASLMechanismHandler(null);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("trace", newArrayList("testDoSASLBindAnonymous"));
 
     try (Socket s = newSocket())
@@ -399,7 +359,7 @@
     AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler();
     handler.initializeSASLMechanismHandler(null);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     try (Socket s = newSocket())
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -408,8 +368,6 @@
     handler.finalizeSASLMechanismHandler();
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS
    * authentication is enabled in the server and multiple trace values are
@@ -417,14 +375,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindAnonymousMultivaluedTrace()
          throws Exception
   {
     AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler();
     handler.initializeSASLMechanismHandler(null);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("trace",
         newArrayList("testDoSASLBindAnonymousMultivaluedTrace", "aSecondTraceStringWhichIsInvalid"));
 
@@ -439,8 +397,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS
    * authentication is enabled in the server and an invalid SASL property is
@@ -448,14 +404,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindAnonymousInvalidProperty()
          throws Exception
   {
     AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler();
     handler.initializeSASLMechanismHandler(null);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("invalid", newArrayList("testDoSASLBindAnonymousInvalidProperty"));
 
     try (Socket s = newSocket())
@@ -469,8 +425,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS
    * authentication is enabled in the server and the request includes the
@@ -485,10 +439,10 @@
     AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler();
     handler.initializeSASLMechanismHandler(null);
 
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     requestControls.add(new PasswordPolicyRequestControl());
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("trace", newArrayList("testDoSASLBindAnonymous"));
     try (Socket s = newSocket())
     {
@@ -499,15 +453,13 @@
     handler.finalizeSASLMechanismHandler();
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which CRAM-MD5
    * authentication is disabled in the server.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindCRAMMD5Disabled()
          throws Exception
   {
@@ -530,8 +482,7 @@
          DirectoryServer.getSASLMechanismHandler("CRAM-MD5");
     DirectoryServer.deregisterSASLMechanismHandler("CRAM-MD5");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try
@@ -544,8 +495,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which CRAM-MD5
    * authentication is enabled in the server.
@@ -571,61 +520,54 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     cramMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which an authID was provided that doesn't map to any user.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindCRAMMD5InvalidAuthID()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     cramMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which an empty authID was provided.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindCRAMMD5EmptyAuthID()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList(""));
 
     cramMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which the provided password was incorrect.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindCRAMMD5InvalidPassword()
          throws Exception
   {
@@ -644,8 +586,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try (Socket s = newSocket())
@@ -655,15 +596,13 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which the specified user doesn't have a reversible password.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindCRAMMD5NoReversiblePassword()
          throws Exception
   {
@@ -680,61 +619,55 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     cramMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which the provided SASL properties were null.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindCRAMMD5NullProperties()
          throws Exception
   {
-    LinkedHashMap<String,List<String>> saslProperties = null;
+    Map<String, List<String>> saslProperties = null;
 
     cramMd5SaslBind(saslProperties);
   }
 
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which the provided SASL properties were empty.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindCRAMMD5EmptyProperties()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     cramMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in
    * which multiple authID values were provided
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindCRAMMD5MultipleAuthIDs()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test", "u:test.user"));
 
     cramMd5SaslBind(saslProperties);
@@ -746,21 +679,19 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindCRAMMD5InvalidSASLProperty()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("invalid", newArrayList("foo"));
 
     cramMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which CRAM-MD5
    * authentication is enabled in the server and the password policy request
@@ -787,11 +718,10 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     requestControls.add(new PasswordPolicyRequestControl());
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     try (Socket s = newSocket())
     {
@@ -802,15 +732,13 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5
    * authentication is disabled in the server.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindDigestMD5Disabled()
          throws Exception
   {
@@ -829,13 +757,11 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
     SASLMechanismHandler<?> digestMD5Handler =
          DirectoryServer.getSASLMechanismHandler("DIGEST-MD5");
     DirectoryServer.deregisterSASLMechanismHandler("DIGEST-MD5");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
 
@@ -850,8 +776,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5
    * authentication is enabled in the server.
@@ -877,8 +801,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try (Socket s = newSocket())
@@ -888,8 +811,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5
    * authentication is enabled in the server and an authz ID was provided.
@@ -915,8 +836,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try (Socket s = newSocket())
@@ -926,119 +846,104 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties are <CODE>null</CODE>.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5NullProperties()
          throws Exception
   {
-
-    LinkedHashMap<String,List<String>> saslProperties = null;
+    Map<String, List<String>> saslProperties = null;
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties are empty.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5EmptyProperties()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain an invalid property.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5InvalidProperty()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("invalid", newArrayList("foo"));
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain multiple values for the authID property.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5MultipleAuthIDs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
-    ArrayList<String> propList = newArrayList("dn:uid=test.user,o=test");
+    List<String> propList = newArrayList("dn:uid=test.user,o=test");
     propList.add("u:test.user");
     saslProperties.put("authid", propList);
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain an empty authID.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5MEmptyAuthID()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList(""));
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain multiple values for the realm property.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5MultipleRealms()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test", "dc=example,dc=com"));
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain a valid quality of protection.
@@ -1064,8 +969,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("qop", newArrayList("auth"));
 
@@ -1083,11 +987,11 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5UnsupportedQoPAuthInt()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
     saslProperties.put("qop", newArrayList("auth-int"));
@@ -1095,8 +999,6 @@
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain the unsupported confidentiality quality
@@ -1104,11 +1006,11 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5UnsupportedQoPAuthConf()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
     saslProperties.put("qop", newArrayList("auth-conf"));
@@ -1116,19 +1018,17 @@
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain an invalid quality of protection.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5InvalidQoP()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
     saslProperties.put("qop", newArrayList("invalid"));
@@ -1136,18 +1036,17 @@
     digestMd5SaslBind(saslProperties);
   }
 
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain multiple quality of protection values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5MultipleQoPs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
     saslProperties.put("qop", newArrayList("auth", "auth-int", "auth-conf"));
@@ -1155,19 +1054,17 @@
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain multiple digest URIs.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5MultipleDigestURIs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
     saslProperties.put("digest-uri", newArrayList("ldap/value1", "ldap/value2"));
@@ -1175,18 +1072,17 @@
     digestMd5SaslBind(saslProperties);
   }
 
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain multiple authorization IDs.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindDigestMD5MultipleAuthzIDs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("realm", newArrayList("o=test"));
     saslProperties.put("authzid", newArrayList("dn:uid=test.user,o=test", "u:test.user"));
@@ -1194,55 +1090,49 @@
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain an invalid auth ID in the DN form.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindDigestMD5InvalidAuthDN()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:invalid"));
     saslProperties.put("realm", newArrayList("o=test"));
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the
    * DIGEST-MD5 SASL properties contain an auth ID that doesn't map to any user.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindDigestMD5NonExistentAuthID()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:nosuchuser"));
     saslProperties.put("realm", newArrayList("o=test"));
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which an invalid
    * password was provided.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindDigestMD5InvalidPassword()
          throws Exception
   {
@@ -1261,8 +1151,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:nosuchuser"));
     saslProperties.put("realm", newArrayList("o=test"));
 
@@ -1273,15 +1162,13 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the target
    * user does not have a reversible password.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindDigestMD5NoReversiblePassword()
          throws Exception
   {
@@ -1298,16 +1185,13 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:nosuchuser"));
     saslProperties.put("realm", newArrayList("o=test"));
 
     digestMd5SaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5
    * authentication is enabled in the server and the password policy request
@@ -1334,11 +1218,10 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     requestControls.add(new PasswordPolicyRequestControl());
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try (Socket s = newSocket())
@@ -1349,15 +1232,13 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which EXTERNAL
    * authentication is not enabled in the server.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindExternalDisabled()
          throws Exception
   {
@@ -1373,24 +1254,20 @@
          "sn: User",
          "cn: Test User");
 
-
     SASLMechanismHandler<?> externalHandler =
          DirectoryServer.getSASLMechanismHandler("EXTERNAL");
     DirectoryServer.deregisterSASLMechanismHandler("EXTERNAL");
 
-
     String keyStorePath   = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.keystore";
     String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.truststore";
 
-
     SSLConnectionFactory factory = new SSLConnectionFactory();
     factory.init(false, keyStorePath, "password", "client-cert",
                  trustStorePath, "password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort()))
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -1402,8 +1279,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which EXTERNAL
    * authentication is enabled in the server.
@@ -1426,35 +1301,30 @@
          "sn: User",
          "cn: Test User");
 
-
     String keyStorePath   = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.keystore";
     String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.truststore";
 
-
     SSLConnectionFactory factory = new SSLConnectionFactory();
     factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                  "password");
 
-
     try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort()))
     {
-      LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+      Map<String, List<String>> saslProperties = new LinkedHashMap<>();
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
       doSASLBind("EXTERNAL", null, authHandler, saslProperties);
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in the EXTERNAL SASL
    * properties were not empty.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindExternalInvalidProperties()
          throws Exception
   {
@@ -1470,27 +1340,23 @@
          "sn: User",
          "cn: Test User");
 
-
     SASLMechanismHandler<?> externalHandler =
          DirectoryServer.getSASLMechanismHandler("EXTERNAL");
     DirectoryServer.deregisterSASLMechanismHandler("EXTERNAL");
 
-
     String keyStorePath   = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.keystore";
     String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.truststore";
 
-
     SSLConnectionFactory factory = new SSLConnectionFactory();
     factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                  "password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("invalid", newArrayList("foo"));
 
-    try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort());)
+    try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort()))
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
       doSASLBind("EXTERNAL", null, authHandler, saslProperties);
@@ -1524,22 +1390,19 @@
          "sn: User",
          "cn: Test User");
 
-
     String keyStorePath   = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.keystore";
     String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.truststore";
 
-
     SSLConnectionFactory factory = new SSLConnectionFactory();
     factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                  "password");
 
-
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     requestControls.add(new PasswordPolicyRequestControl());
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort()))
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -1548,36 +1411,32 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties list was null.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPINullProperties()
          throws Exception
   {
-    LinkedHashMap<String,List<String>> saslProperties = null;
+    Map<String, List<String>> saslProperties = null;
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties list was empty.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIEmptyProperties()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     gssapiSaslBind(saslProperties);
   }
@@ -1641,7 +1500,7 @@
     }
   }
 
-  private void cramMd5SaslBind(LinkedHashMap<String, List<String>> saslProperties) throws Exception
+  private void cramMd5SaslBind(Map<String, List<String>> saslProperties) throws Exception
   {
     try (Socket s = newSocket())
     {
@@ -1649,7 +1508,7 @@
     }
   }
 
-  private void digestMd5SaslBind(LinkedHashMap<String, List<String>> saslProperties) throws Exception
+  private void digestMd5SaslBind(Map<String, List<String>> saslProperties) throws Exception
   {
     try (Socket s = newSocket())
     {
@@ -1657,7 +1516,7 @@
     }
   }
 
-  private void gssapiSaslBind(LinkedHashMap<String, List<String>> saslProperties) throws Exception
+  private void gssapiSaslBind(Map<String, List<String>> saslProperties) throws Exception
   {
     try (Socket s = newSocket())
     {
@@ -1671,93 +1530,83 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIEmptyAuthID()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList(""));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has multiple authID values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIMultipleAuthIDs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user", "dn:uid=test.user,o=test"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has multiple authzID values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIMultipleAuthzIDs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("authzid", newArrayList("u:test.user", "dn:uid=test.user,o=test"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has multiple KDC values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIMultipleKDCs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("kdc", newArrayList("kdc1", "kdc2"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has multiple quality of protection values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIMultipleQoPs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("qop", newArrayList("auth", "auth-int", "auth-conf"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has an unsupported quality of protection value of
@@ -1765,19 +1614,17 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIUnsupportedQoPAuthInt()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("qop", newArrayList("auth-int"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has an unsupported quality of protection value of
@@ -1785,100 +1632,91 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIUnsupportedQoPAuthConf()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("qop", newArrayList("auth-conf"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has an invalid quality of protection value.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIInvalidQoP()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("qop", newArrayList("invalid"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has multiple realm values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIMultipleRealms()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("realm", newArrayList("realm1", "realm2"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties has an invalid property.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPIInvalidProperty()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("u:test.user"));
     saslProperties.put("invalid", newArrayList("foo"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the
    * provided properties isn't empty but doesn't contain an auth ID.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindGSSAPINoAuthID()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("qop", newArrayList("auth"));
 
     gssapiSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which PLAIN
    * authentication is disabled in the server.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindPlainDisabled()
          throws Exception
   {
@@ -1895,13 +1733,11 @@
          "cn: Test User",
          "userPassword: password");
 
-
     SASLMechanismHandler<?> plainHandler =
          DirectoryServer.getSASLMechanismHandler("PLAIN");
     DirectoryServer.deregisterSASLMechanismHandler("PLAIN");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try (Socket s = newSocket())
@@ -1915,8 +1751,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which PLAIN
    * authentication is enabled in the server.
@@ -1940,8 +1774,7 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     try (Socket s = newSocket())
     {
@@ -1950,53 +1783,47 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN
    * SASL properties are null.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainNullProperties()
          throws Exception
   {
-    LinkedHashMap<String,List<String>> saslProperties = null;
+    Map<String, List<String>> saslProperties = null;
 
     plainSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN
    * SASL properties are empty.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainEmptyProperties()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
 
     plainSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN
    * SASL properties have multiple auth ID values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainMultipleAuthIDs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test", "u:test.user"));
 
     plainSaslBind(saslProperties);
@@ -2008,90 +1835,81 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainZeroLengthAuthID()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList(""));
 
     plainSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN
    * SASL properties have multiple authzID values.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainMultipleAuthzIDs()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("authzid", newArrayList("dn:uid=test.user,o=test", "u:test.user"));
 
     plainSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN
    * SASL properties contains an invalid property.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainInvalidProperty()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     saslProperties.put("invalid", newArrayList("foo"));
 
     plainSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN
    * SASL properties does not contain an auth ID.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { ClientException.class })
+  @Test(expectedExceptions = ClientException.class)
   public void testDoSASLBindPlainNoAuthID()
          throws Exception
   {
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authzid", newArrayList("dn:uid=test.user,o=test"));
 
     plainSaslBind(saslProperties);
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for PLAIN authentication in which
    * the target user does not exist in the server.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindPlainNonExistentUser()
          throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-
     try (Socket s = newSocket())
     {
-      LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+      Map<String, List<String>> saslProperties = new LinkedHashMap<>();
       saslProperties.put("authid", newArrayList("dn:uid=does.not.exist,o=test"));
 
       plain(newLDAPAuthenticationHandler(s, "localhost"), saslProperties);
@@ -2105,7 +1923,7 @@
    * @throws Exception
    *           If an unexpected problem occurs.
    */
-  @Test(expectedExceptions = { LDAPException.class })
+  @Test(expectedExceptions = LDAPException.class)
   public void testDoSASLBindPlainWrongPassword()
          throws Exception
   {
@@ -2122,8 +1940,7 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=does.not.exist,o=test"));
     try (Socket s = newSocket())
     {
@@ -2132,8 +1949,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>doSASLBind</CODE> method for the case in which PLAIN
    * authentication is enabled in the server and the password policy request
@@ -2158,11 +1973,10 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     requestControls.add(new PasswordPolicyRequestControl());
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     try (Socket s = newSocket())
     {
@@ -2172,8 +1986,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for an
    * unauthenticated client connection.
@@ -2191,8 +2003,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after a simple anonymous bind.
@@ -2203,8 +2013,8 @@
   public void testRequestAuthorizationIdentitySimpleAnonymous()
          throws Exception
   {
-    ArrayList<Control> requestControls = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
 
     try (Socket s = newSocket())
     {
@@ -2224,8 +2034,8 @@
   public void testRequestAuthorizationIdentitySimpleRootUser()
          throws Exception
   {
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     try (Socket s = newSocket())
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -2235,8 +2045,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after a simple bind as a normal user.
@@ -2260,9 +2068,8 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    ArrayList<Control> requestControls  = new ArrayList<>();
-    ArrayList<Control> responseControls = new ArrayList<>();
+    List<Control> requestControls = new ArrayList<>();
+    List<Control> responseControls = new ArrayList<>();
     try (Socket s = newSocket())
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -2272,8 +2079,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after a SASL ANONYMOUS bind.
@@ -2287,7 +2092,7 @@
     AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler();
     handler.initializeSASLMechanismHandler(null);
 
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("trace", newArrayList("testDoSASLBindAnonymous"));
     try (Socket s = newSocket())
     {
@@ -2298,8 +2103,6 @@
     handler.finalizeSASLMechanismHandler();
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after a CRAM-MD5 bind.
@@ -2325,8 +2128,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     try (Socket s = newSocket())
     {
@@ -2336,8 +2138,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after a DIGEST-MD5 bind.
@@ -2363,8 +2163,7 @@
          "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
               "cn=Password Policies,cn=config");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
 
     try (Socket s = newSocket())
@@ -2375,8 +2174,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after an EXTERNAL bind.
@@ -2399,19 +2196,16 @@
          "sn: User",
          "cn: Test User");
 
-
     String keyStorePath   = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.keystore";
     String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator +
                             "config" + File.separator + "client.truststore";
 
-
     SSLConnectionFactory factory = new SSLConnectionFactory();
     factory.init(false, keyStorePath, "password", "client-cert", trustStorePath,
                  "password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort()))
     {
       LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost");
@@ -2420,8 +2214,6 @@
     }
   }
 
-
-
   /**
    * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client
    * connection after a PLAIN bind.
@@ -2445,8 +2237,7 @@
          "cn: Test User",
          "userPassword: password");
 
-
-    LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>();
+    Map<String, List<String>> saslProperties = new LinkedHashMap<>();
     saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test"));
     try (Socket s = newSocket())
     {

--
Gitblit v1.10.0