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

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java |   51 +++++++++++++++++++++++++
 opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java                          |   49 ++++++++++++++++++++++--
 opends/src/messages/messages/extension.properties                                                                       |    3 +
 3 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/opends/src/messages/messages/extension.properties b/opends/src/messages/messages/extension.properties
index 9ca6451..cbde8c7 100644
--- a/opends/src/messages/messages/extension.properties
+++ b/opends/src/messages/messages/extension.properties
@@ -1495,3 +1495,6 @@
 MILD_ERR_LDAP_PTA_CONNECTION_SEARCH_FAILED_605=The remote LDAP server at %s:%d \
  for LDAP PTA policy "%s" returned an error while searching "%s" using the \
  filter "%s": response code %d (%s) and error message "%s"
+MILD_ERR_LDAP_PTA_INVALID_PORT_NUMBER_606=The configuration of LDAP PTA policy \
+ "%s" is invalid because the remote LDAP server address "%s" specifies a port \
+ number which is invalid. Port numbers should be greater than 0 and less than 65536 
diff --git a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
index ad6ae4c..d4f332b 100644
--- a/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
+++ b/opends/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyFactory.java
@@ -80,7 +80,6 @@
   // TODO: handle password policy response controls? AD?
   // TODO: periodically ping offline servers in order to detect when they come
   // back.
-  // FIXME: validate host/port (check port in range).
 
   /**
    * An LDAP connection which will be used in order to search for or
@@ -1637,8 +1636,8 @@
         final LDAPPassThroughAuthenticationPolicyCfg configuration,
         final List<Message> unacceptableReasons)
     {
-      // The configuration is always valid.
-      return true;
+      return LDAPPassThroughAuthenticationPolicyFactory.this
+          .isConfigurationAcceptable(configuration, unacceptableReasons);
     }
 
 
@@ -1674,6 +1673,11 @@
     {
       this.configuration = configuration;
 
+      // Use two pools per server: one for authentication (bind) and one for
+      // searches. Even if the searches are performed anonymously we cannot use
+      // the same pool, otherwise they will be performed as the most recently
+      // authenticated user.
+
       // Create load-balancers for primary servers.
       final LoadBalancer primarySearchLoadBalancer;
       final LoadBalancer primaryBindLoadBalancer;
@@ -1858,7 +1862,44 @@
       final LDAPPassThroughAuthenticationPolicyCfg configuration,
       final List<Message> unacceptableReasons)
   {
-    // The configuration is always valid.
+    // Check that the port numbers are valid. We won't actually try and connect
+    // to the server since they may not be available (hence we have fail-over
+    // capabilities).
+    boolean configurationIsAcceptable = true;
+
+    for (String hostPort : configuration.getPrimaryRemoteLDAPServer())
+    {
+      configurationIsAcceptable &= isServerAddressValid(configuration,
+          unacceptableReasons, hostPort);
+    }
+
+    for (String hostPort : configuration.getSecondaryRemoteLDAPServer())
+    {
+      configurationIsAcceptable &= isServerAddressValid(configuration,
+          unacceptableReasons, hostPort);
+    }
+
+    return configurationIsAcceptable;
+  }
+
+
+
+  private static boolean isServerAddressValid(
+      final LDAPPassThroughAuthenticationPolicyCfg configuration,
+      final List<Message> unacceptableReasons, String hostPort)
+  {
+    final int colonIndex = hostPort.lastIndexOf(":");
+    final int port = Integer.parseInt(hostPort.substring(colonIndex + 1));
+    if (port < 1 || port > 65535)
+    {
+      if (unacceptableReasons != null)
+      {
+        Message msg = ERR_LDAP_PTA_INVALID_PORT_NUMBER.get(
+            String.valueOf(configuration.dn()), hostPort);
+        unacceptableReasons.add(msg);
+      }
+      return false;
+    }
     return true;
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
index 19ccff8..c29b25c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
@@ -39,6 +39,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.opends.messages.Message;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.meta.LDAPPassThroughAuthenticationPolicyCfgDefn.MappingPolicy;
@@ -2491,6 +2492,56 @@
 
 
 
+  /**
+   * Tests configuration validation.
+   *
+   * @param cfg
+   *          The configuration to be tested.
+   * @param isValid
+   *          Whether or not the provided configuration is valid.
+   * @throws Exception
+   *           If an unexpected exception occurred.
+   */
+  @Test(enabled = true, dataProvider = "testIsConfigurationAcceptableData")
+  public void testIsConfigurationAcceptable(
+      final LDAPPassThroughAuthenticationPolicyCfg cfg, final boolean isValid)
+      throws Exception
+  {
+    final LDAPPassThroughAuthenticationPolicyFactory factory = new LDAPPassThroughAuthenticationPolicyFactory();
+    assertEquals(
+        factory.isConfigurationAcceptable(cfg, new LinkedList<Message>()),
+        isValid);
+  }
+
+
+
+  /**
+   * Returns test data for {@link #testIsConfigurationAcceptable}.
+   *
+   * @return Test data for {@link #testIsConfigurationAcceptable}.
+   */
+  @DataProvider
+  public Object[][] testIsConfigurationAcceptableData()
+  {
+    // @formatter:off
+    return new Object[][] {
+        /* cfg, isValid */
+        { mockCfg().withPrimaryServer("test:1"), true },
+        { mockCfg().withPrimaryServer("test:65535"), true },
+        { mockCfg().withPrimaryServer("test:0"), false },
+        { mockCfg().withPrimaryServer("test:65536"), false },
+        { mockCfg().withPrimaryServer("test:1000000"), false },
+        { mockCfg().withSecondaryServer("test:1"), true },
+        { mockCfg().withSecondaryServer("test:65535"), true },
+        { mockCfg().withSecondaryServer("test:0"), false },
+        { mockCfg().withSecondaryServer("test:65536"), false },
+        { mockCfg().withSecondaryServer("test:1000000"), false },
+    };
+    // @formatter:on
+  }
+
+
+
   MockPolicyCfg mockCfg()
   {
     return new MockPolicyCfg();

--
Gitblit v1.10.0