From 23a8bb37f4f831f7d150720ad0d169f18fc159d3 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 09 Sep 2011 12:53:40 +0000
Subject: [PATCH] Issue OPENDJ-262: Implement pass through authentication (PTA)

---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java | 1459 ++++++++++++++++++++++++++++++++++-----------------------
 1 files changed, 870 insertions(+), 589 deletions(-)

diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
index 587f244..19ccff8 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
@@ -858,14 +858,6 @@
 
 
 
-    MockServer thenAccept()
-    {
-      actions.add(new AcceptAction());
-      return this;
-    }
-
-
-
     void assertNoExceptions() throws Exception
     {
       if (e != null)
@@ -951,9 +943,17 @@
 
 
 
+    MockServer thenAccept()
+    {
+      actions.add(new AcceptAction());
+      return this;
+    }
+
+
+
     MockServer thenBlock()
     {
-      BlockAction action = new BlockAction();
+      final BlockAction action = new BlockAction();
       actions.add(action);
       blockers.add(action);
       return this;
@@ -987,7 +987,7 @@
 
     void unblock() throws Exception
     {
-      BlockAction action = blockers.poll();
+      final BlockAction action = blockers.poll();
       assertNotNull(action);
       action.release();
     }
@@ -1523,6 +1523,828 @@
 
 
   /**
+   * Tests valid bind which times out at the client. These should trigger a
+   * CLIENT_SIDE_TIMEOUT result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryBindClientTimeout() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg()
+        .withConnectionTimeout(500);
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept().thenBlock().start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.simpleBind(ByteString.valueOf(searchBindDNString),
+          ByteString.valueOf(userPassword));
+      fail("Bind attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_TIMEOUT,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.unblock();
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid bind which never receives a response because the server
+   * abruptly closes the connection.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryBindConnectionClosed() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept()
+        .thenReceive(1, newBindRequest(searchBindDNString, userPassword))
+        .thenClose().start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.simpleBind(ByteString.valueOf(searchBindDNString),
+          ByteString.valueOf(userPassword));
+      fail("Bind attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_SERVER_DOWN,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests bind which receives a disconnect notification. The error result code
+   * should be passed back to the called.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryBindDisconnectNotification()
+      throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1, newBindRequest(searchBindDNString, userPassword))
+        .thenSend(0 /* disconnect ID */,
+            newDisconnectNotification(ResultCode.UNAVAILABLE)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.simpleBind(ByteString.valueOf(searchBindDNString),
+          ByteString.valueOf(userPassword));
+      fail("Bind attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      // Should be the result code sent by the server.
+      assertEquals(e.getResultCode(), ResultCode.UNAVAILABLE, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests bind with invalid credentials which should return a
+   * INVALID_CREDENTIALS result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryBindInvalidCredentials()
+      throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept()
+        .thenReceive(1, newBindRequest(searchBindDNString, userPassword))
+        .thenSend(1, newBindResult(ResultCode.INVALID_CREDENTIALS)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.simpleBind(ByteString.valueOf(searchBindDNString),
+          ByteString.valueOf(userPassword));
+      fail("Bind attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.INVALID_CREDENTIALS,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests bind which returns an error result. The error result code should be
+   * passed back to the caller.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryBindOtherError() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept()
+        .thenReceive(1, newBindRequest(searchBindDNString, userPassword))
+        .thenSend(1, newBindResult(ResultCode.UNAVAILABLE)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.simpleBind(ByteString.valueOf(searchBindDNString),
+          ByteString.valueOf(userPassword));
+      fail("Bind attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.UNAVAILABLE, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid bind returning success.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryBindSuccess() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept()
+        .thenReceive(1, newBindRequest(searchBindDNString, userPassword))
+        .thenSend(1, newBindResult(ResultCode.SUCCESS)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.simpleBind(ByteString.valueOf(searchBindDNString),
+          ByteString.valueOf(userPassword));
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests successful connect/unbind.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryConnectAndUnbind() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept()
+        .thenReceive(1, new UnbindRequestProtocolOp()).thenClose().start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    try
+    {
+      final Connection connection = factory.getConnection();
+      connection.close();
+    }
+    finally
+    {
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests that invalid ports are handled properly. These should trigger a
+   * CLIENT_SIDE_CONNECT_ERROR result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryConnectPortNotInUse() throws Exception
+  {
+    // Grab an unused port.
+    final ServerSocket socket = TestCaseUtils.bindFreePort();
+    final int port = socket.getLocalPort();
+
+    // FIXME: will it matter if the port is left in TIME_WAIT?
+    socket.close();
+
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", port, cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      fail("Connect attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_CONNECT_ERROR,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+    }
+  }
+
+
+
+  /**
+   * Tests that unknown hosts are handled properly. These should trigger a
+   * CLIENT_SIDE_CONNECT_ERROR result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactoryConnectUnknownHost() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // FIXME: can we guarantee that "unknownhost" does not exist?
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "unknownhost", 31415, cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      fail("Connect attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_CONNECT_ERROR,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+    }
+  }
+
+
+
+  /**
+   * Tests valid search which times out at the client. These should trigger a
+   * CLIENT_SIDE_TIMEOUT result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchClientTimeout() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg()
+        .withConnectionTimeout(500);
+
+    // Mock server.
+    final MockServer server = mockServer(cfg).thenAccept().thenBlock().start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(objectClass=*)"));
+      fail("Search attempt should have timed out");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_TIMEOUT,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.unblock();
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search which never receives a response because the server
+   * abruptly closes the connection.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchConnectionClosed()
+      throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenClose().start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_SERVER_DOWN,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search which receives a disconnect notification. The error
+   * result code should be passed back to the called.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchDisconnectNotification()
+      throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(0 /* disconnect ID */,
+            newDisconnectNotification(ResultCode.UNAVAILABLE)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      // Should be the result code sent by the server.
+      assertEquals(e.getResultCode(), ResultCode.UNAVAILABLE, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search returning no results are handled properly. These should
+   * trigger a CLIENT_SIDE_NO_RESULTS_RETURNED result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchNoResults() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(1, newSearchResult(ResultCode.SUCCESS)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(),
+          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests search returning no entries and an error result. The error result
+   * code should be passed back to the caller.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchOtherError() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(1, newSearchResult(ResultCode.UNAVAILABLE)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      // Should be the result code sent by the server.
+      assertEquals(e.getResultCode(), ResultCode.UNAVAILABLE, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search returning a single entry followed by a size limit
+   * exceeded error are handled properly. These should trigger a
+   * CLIENT_SIDE_MORE_RESULTS_TO_RETURN result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchSizeLimit() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(1, newSearchEntry(adDNString))
+        .thenSend(1, newSearchResult(ResultCode.SIZE_LIMIT_EXCEEDED)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(),
+          ResultCode.CLIENT_SIDE_MORE_RESULTS_TO_RETURN, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search returning a single entry works properly.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchSuccess() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(1, newSearchEntry(adDNString))
+        .thenSend(1, newSearchResult(ResultCode.SUCCESS)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      final ByteString username = connection.search(searchBindDN,
+          SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      assertEquals(username, ByteString.valueOf(adDNString));
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search returning a single entry followed by a time limit
+   * exceeded error are handled properly. These should trigger a
+   * CLIENT_SIDE_MORE_RESULTS_TO_RETURN result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchTimeLimit() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(1, newSearchEntry(adDNString))
+        .thenSend(1, newSearchResult(ResultCode.TIME_LIMIT_EXCEEDED)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(), ResultCode.TIME_LIMIT_EXCEEDED,
+          e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
+   * Tests valid search returning many results are handled properly. These
+   * should trigger a CLIENT_SIDE_MORE_RESULTS_TO_RETURN result code.
+   *
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true)
+  public void testLDAPConnectionFactorySearchTooManyResults() throws Exception
+  {
+    // Mock configuration.
+    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
+
+    // Mock server.
+    final MockServer server = mockServer(cfg)
+        .thenAccept()
+        .thenReceive(1,
+            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
+        .thenSend(1, newSearchEntry(adDNString))
+        .thenSend(1, newSearchEntry(opendjDNString))
+        .thenSend(1, newSearchResult(ResultCode.SUCCESS)).start();
+
+    // Test connect and close.
+    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
+        "127.0.0.1", server.getPort(), cfg);
+    Connection connection = null;
+    try
+    {
+      connection = factory.getConnection();
+      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
+          SearchFilter.createFilterFromString("(uid=aduser)"));
+      fail("Search attempt should have failed");
+    }
+    catch (final DirectoryException e)
+    {
+      assertEquals(e.getResultCode(),
+          ResultCode.CLIENT_SIDE_MORE_RESULTS_TO_RETURN, e.getMessage());
+    }
+    finally
+    {
+      if (connection != null)
+      {
+        connection.close();
+      }
+      server.stop();
+    }
+  }
+
+
+
+  /**
    * Tests the different mapping policies: connection attempts will succeed, as
    * will any searches, but the final user bind may or may not succeed depending
    * on the provided result code.
@@ -1669,565 +2491,6 @@
 
 
 
-  /**
-   * Tests that unknown hosts are handled properly. These should trigger a
-   * CLIENT_SIDE_CONNECT_ERROR result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactoryConnectUnknownHost() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // FIXME: can we guarantee that "unknownhost" does not exist?
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "unknownhost", 31415, cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      fail("Connect attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_CONNECT_ERROR,
-          e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-    }
-  }
-
-
-
-  /**
-   * Tests that invalid ports are handled properly. These should trigger a
-   * CLIENT_SIDE_CONNECT_ERROR result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactoryConnectPortNotInUse() throws Exception
-  {
-    // Grab an unused port.
-    ServerSocket socket = TestCaseUtils.bindFreePort();
-    int port = socket.getLocalPort();
-
-    // FIXME: will it matter if the port is left in TIME_WAIT?
-    socket.close();
-
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", port, cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      fail("Connect attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_CONNECT_ERROR,
-          e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-    }
-  }
-
-
-
-  /**
-   * Tests successful connect/unbind.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactoryConnectAndUnbind() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg).thenAccept()
-        .thenReceive(1, new UnbindRequestProtocolOp()).thenClose().start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    try
-    {
-      Connection connection = factory.getConnection();
-      connection.close();
-    }
-    finally
-    {
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search returning a single entry works properly.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchSuccess() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(1, newSearchEntry(adDNString))
-        .thenSend(1, newSearchResult(ResultCode.SUCCESS)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      ByteString username = connection.search(searchBindDN,
-          SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      assertEquals(username, ByteString.valueOf(adDNString));
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search returning no results are handled properly. These should
-   * trigger a CLIENT_SIDE_NO_RESULTS_RETURNED result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchNoResults() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(1, newSearchResult(ResultCode.SUCCESS)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(),
-          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search returning many results are handled properly. These
-   * should trigger a CLIENT_SIDE_MORE_RESULTS_TO_RETURN result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchTooManyResults() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(1, newSearchEntry(adDNString))
-        .thenSend(1, newSearchEntry(opendjDNString))
-        .thenSend(1, newSearchResult(ResultCode.SUCCESS)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(),
-          ResultCode.CLIENT_SIDE_MORE_RESULTS_TO_RETURN, e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search returning a single entry followed by a size limit
-   * exceeded error are handled properly. These should trigger a
-   * CLIENT_SIDE_MORE_RESULTS_TO_RETURN result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchSizeLimit() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(1, newSearchEntry(adDNString))
-        .thenSend(1, newSearchResult(ResultCode.SIZE_LIMIT_EXCEEDED)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(),
-          ResultCode.CLIENT_SIDE_MORE_RESULTS_TO_RETURN, e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search which times out at the client. These should trigger a
-   * CLIENT_SIDE_TIMEOUT result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchClientTimeout() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg()
-        .withConnectionTimeout(500);
-
-    // Mock server.
-    final MockServer server = mockServer(cfg).thenAccept().thenBlock().start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(objectClass=*)"));
-      fail("Search attempt should have timed out");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_TIMEOUT,
-          e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.unblock();
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search returning a single entry followed by a time limit
-   * exceeded error are handled properly. These should trigger a
-   * CLIENT_SIDE_MORE_RESULTS_TO_RETURN result code.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchTimeLimit() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(1, newSearchEntry(adDNString))
-        .thenSend(1, newSearchResult(ResultCode.TIME_LIMIT_EXCEEDED)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(), ResultCode.TIME_LIMIT_EXCEEDED,
-          e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search no entries and an error result. The error result code
-   * should be passed back to the called.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchOtherError() throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(1, newSearchResult(ResultCode.UNAVAILABLE)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      // Should be the result code sent by the server.
-      assertEquals(e.getResultCode(), ResultCode.UNAVAILABLE, e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search which receives a disconnect notification. The error
-   * result code should be passed back to the called.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchDisconnectNotification()
-      throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenSend(0 /* disconnect ID */,
-            newDisconnectNotification(ResultCode.UNAVAILABLE)).start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      // Should be the result code sent by the server.
-      assertEquals(e.getResultCode(), ResultCode.UNAVAILABLE, e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  /**
-   * Tests valid search which never receives a response because the server
-   * abruptly closes the connection.
-   *
-   * @throws Exception
-   *           If an unexpected exception occurred.
-   */
-  @Test(enabled = true)
-  public void testLDAPConnectionFactorySearchConnectionClosed()
-      throws Exception
-  {
-    // Mock configuration.
-    final LDAPPassThroughAuthenticationPolicyCfg cfg = mockCfg();
-
-    // Mock server.
-    final MockServer server = mockServer(cfg)
-        .thenAccept()
-        .thenReceive(1,
-            newSearchRequest(searchBindDNString, "(uid=aduser)", cfg))
-        .thenClose().start();
-
-    // Test connect and close.
-    final LDAPConnectionFactory factory = new LDAPConnectionFactory(
-        "127.0.0.1", server.getPort(), cfg);
-    Connection connection = null;
-    try
-    {
-      connection = factory.getConnection();
-      connection.search(searchBindDN, SearchScope.WHOLE_SUBTREE,
-          SearchFilter.createFilterFromString("(uid=aduser)"));
-      fail("Search attempt should have failed");
-    }
-    catch (DirectoryException e)
-    {
-      assertEquals(e.getResultCode(), ResultCode.CLIENT_SIDE_SERVER_DOWN,
-          e.getMessage());
-    }
-    finally
-    {
-      if (connection != null)
-      {
-        connection.close();
-      }
-      server.stop();
-    }
-  }
-
-
-
-  // Bind success
-  // Bind authn failure (pwd)
-  // Bind auth failure (username)
-  // Bind auth timeout
-  // Bind auth fatal error
-  // Bind auth non-fatal error
-  // Bind + notice of disconnect
-  // Bind + server close
-
   MockPolicyCfg mockCfg()
   {
     return new MockPolicyCfg();
@@ -2244,10 +2507,44 @@
 
 
 
-  SearchRequestProtocolOp newSearchRequest(String dn, String filter,
-      LDAPPassThroughAuthenticationPolicyCfg cfg) throws LDAPException
+  BindRequestProtocolOp newBindRequest(final String dn, final String password)
+      throws LDAPException
   {
-    int timeout = (int) (cfg.getConnectionTimeout() / 1000);
+    return new BindRequestProtocolOp(ByteString.valueOf(dn), 3,
+        ByteString.valueOf(password));
+  }
+
+
+
+  BindResponseProtocolOp newBindResult(final ResultCode resultCode)
+  {
+    return new BindResponseProtocolOp(resultCode.getIntValue());
+  }
+
+
+
+  ExtendedResponseProtocolOp newDisconnectNotification(
+      final ResultCode resultCode)
+  {
+    return new ExtendedResponseProtocolOp(resultCode.getIntValue(), null, null,
+        null, OID_NOTICE_OF_DISCONNECTION, null);
+  }
+
+
+
+  SearchResultEntryProtocolOp newSearchEntry(final String dn)
+      throws DirectoryException
+  {
+    return new SearchResultEntryProtocolOp(DN.decode(dn));
+  }
+
+
+
+  SearchRequestProtocolOp newSearchRequest(final String dn,
+      final String filter, final LDAPPassThroughAuthenticationPolicyCfg cfg)
+      throws LDAPException
+  {
+    final int timeout = (int) (cfg.getConnectionTimeout() / 1000);
     return new SearchRequestProtocolOp(ByteString.valueOf(dn),
         SearchScope.WHOLE_SUBTREE, DereferencePolicy.DEREF_ALWAYS, 1, timeout,
         true, RawFilter.create(filter),
@@ -2256,24 +2553,8 @@
 
 
 
-  SearchResultEntryProtocolOp newSearchEntry(String dn)
-      throws DirectoryException
-  {
-    return new SearchResultEntryProtocolOp(DN.decode(dn));
-  }
-
-
-
-  SearchResultDoneProtocolOp newSearchResult(ResultCode resultCode)
+  SearchResultDoneProtocolOp newSearchResult(final ResultCode resultCode)
   {
     return new SearchResultDoneProtocolOp(resultCode.getIntValue());
   }
-
-
-
-  ExtendedResponseProtocolOp newDisconnectNotification(ResultCode resultCode)
-  {
-    return new ExtendedResponseProtocolOp(resultCode.getIntValue(), null, null,
-        null, OID_NOTICE_OF_DISCONNECTION, null);
-  }
 }

--
Gitblit v1.10.0