You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by cn...@apache.org on 2016/06/03 23:46:07 UTC

[2/3] hadoop git commit: HADOOP-13105. Support timeouts in LDAP queries in LdapGroupsMapping. Contributed by Mingliang Liu.

HADOOP-13105. Support timeouts in LDAP queries in LdapGroupsMapping. Contributed by Mingliang Liu.

(cherry picked from commit d82bc8501869be78780fc09752dbf7af918c14af)


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/5e6ee5aa
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/5e6ee5aa
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/5e6ee5aa

Branch: refs/heads/branch-2
Commit: 5e6ee5aafb9b9f200d906444e4731cfc60ac6ebb
Parents: 8ebd89d
Author: Chris Nauroth <cn...@apache.org>
Authored: Fri Jun 3 16:38:30 2016 -0700
Committer: Chris Nauroth <cn...@apache.org>
Committed: Fri Jun 3 16:38:38 2016 -0700

----------------------------------------------------------------------
 .../hadoop/security/LdapGroupsMapping.java      |  12 ++
 .../src/main/resources/core-default.xml         |  24 ++++
 .../hadoop/security/TestLdapGroupsMapping.java  | 140 +++++++++++++++++++
 3 files changed, 176 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/5e6ee5aa/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java
index 498b92e..da87369 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/LdapGroupsMapping.java
@@ -179,6 +179,13 @@ public class LdapGroupsMapping
     LDAP_CONFIG_PREFIX + ".directory.search.timeout";
   public static final int DIRECTORY_SEARCH_TIMEOUT_DEFAULT = 10000; // 10s
 
+  public static final String CONNECTION_TIMEOUT =
+      LDAP_CONFIG_PREFIX + ".connection.timeout.ms";
+  public static final int CONNECTION_TIMEOUT_DEFAULT = 60 * 1000; // 60 seconds
+  public static final String READ_TIMEOUT =
+      LDAP_CONFIG_PREFIX + ".read.timeout.ms";
+  public static final int READ_TIMEOUT_DEFAULT = 60 * 1000; // 60 seconds
+
   private static final Log LOG = LogFactory.getLog(LdapGroupsMapping.class);
 
   private static final SearchControls SEARCH_CONTROLS = new SearchControls();
@@ -432,6 +439,11 @@ public class LdapGroupsMapping
       env.put(Context.SECURITY_PRINCIPAL, bindUser);
       env.put(Context.SECURITY_CREDENTIALS, bindPassword);
 
+      env.put("com.sun.jndi.ldap.connect.timeout", conf.get(CONNECTION_TIMEOUT,
+          String.valueOf(CONNECTION_TIMEOUT_DEFAULT)));
+      env.put("com.sun.jndi.ldap.read.timeout", conf.get(READ_TIMEOUT,
+          String.valueOf(READ_TIMEOUT_DEFAULT)));
+
       ctx = new InitialDirContext(env);
     }
 

http://git-wip-us.apache.org/repos/asf/hadoop/blob/5e6ee5aa/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml
index 3f279d6..b84741a 100644
--- a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml
+++ b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml
@@ -175,6 +175,30 @@
 </property>
 
 <property>
+  <name>hadoop.security.group.mapping.ldap.connection.timeout.ms</name>
+  <value>60000</value>
+  <description>
+    This property is the connection timeout (in milliseconds) for LDAP
+    operations. If the LDAP provider doesn't establish a connection within the
+    specified period, it will abort the connect attempt. Non-positive value
+    means no LDAP connection timeout is specified in which case it waits for the
+    connection to establish until the underlying network times out.
+  </description>
+</property>
+
+<property>
+  <name>hadoop.security.group.mapping.ldap.read.timeout.ms</name>
+  <value>60000</value>
+  <description>
+    This property is the read timeout (in milliseconds) for LDAP
+    operations. If the LDAP provider doesn't get a LDAP response within the
+    specified period, it will abort the read attempt. Non-positive value
+    means no read timeout is specified in which case it waits for the response
+    infinitely.
+  </description>
+</property>
+
+<property>
   <name>hadoop.security.group.mapping.ldap.url</name>
   <value></value>
   <description>

http://git-wip-us.apache.org/repos/asf/hadoop/blob/5e6ee5aa/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java
index 9319016..9f9f994 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestLdapGroupsMapping.java
@@ -17,8 +17,13 @@
  */
 package org.apache.hadoop.security;
 
+import static org.apache.hadoop.security.LdapGroupsMapping.CONNECTION_TIMEOUT;
+import static org.apache.hadoop.security.LdapGroupsMapping.READ_TIMEOUT;
+import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.times;
@@ -29,8 +34,11 @@ import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.Writer;
+import java.net.ServerSocket;
+import java.net.Socket;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 import javax.naming.CommunicationException;
 import javax.naming.NamingException;
@@ -38,16 +46,38 @@ import javax.naming.directory.SearchControls;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.io.IOUtils;
 import org.apache.hadoop.security.alias.CredentialProvider;
 import org.apache.hadoop.security.alias.CredentialProviderFactory;
 import org.apache.hadoop.security.alias.JavaKeyStoreProvider;
 import org.apache.hadoop.test.GenericTestUtils;
+
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 @SuppressWarnings("unchecked")
 public class TestLdapGroupsMapping extends TestLdapGroupsMappingBase {
+
+  private static final Logger LOG = LoggerFactory.getLogger(
+      TestLdapGroupsMapping.class);
+
+  /**
+   * To construct a LDAP InitialDirContext object, it will firstly initiate a
+   * protocol session to server for authentication. After a session is
+   * established, a method of authentication is negotiated between the server
+   * and the client. When the client is authenticated, the LDAP server will send
+   * a bind response, whose message contents are bytes as the
+   * {@link #AUTHENTICATE_SUCCESS_MSG}. After receiving this bind response
+   * message, the LDAP context is considered connected to the server and thus
+   * can issue query requests for determining group membership.
+   */
+  private static final byte[] AUTHENTICATE_SUCCESS_MSG =
+      {48, 12, 2, 1, 1, 97, 7, 10, 1, 0, 4, 0, 4, 0};
+
   @Before
   public void setupMocks() throws NamingException {
     when(getUserSearchResult().getNameInNamespace()).
@@ -176,4 +206,114 @@ public class TestLdapGroupsMapping extends TestLdapGroupsMappingBase {
     // extract password
     Assert.assertEquals("", mapping.getPassword(conf,"invalid-alias", ""));
   }
+
+  /**
+   * Test that if the {@link LdapGroupsMapping#CONNECTION_TIMEOUT} is set in the
+   * configuration, the LdapGroupsMapping connection will timeout by this value
+   * if it does not get a LDAP response from the server.
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  @Test (timeout = 30000)
+  public void testLdapConnectionTimeout()
+      throws IOException, InterruptedException {
+    final int connectionTimeoutMs = 3 * 1000; // 3s
+    try (ServerSocket serverSock = new ServerSocket(0)) {
+      final CountDownLatch finLatch = new CountDownLatch(1);
+
+      // Below we create a LDAP server which will accept a client request;
+      // but it will never reply to the bind (connect) request.
+      // Client of this LDAP server is expected to get a connection timeout.
+      final Thread ldapServer = new Thread(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            try (Socket ignored = serverSock.accept()) {
+              finLatch.await();
+            }
+          } catch (Exception e) {
+            e.printStackTrace();
+          }
+        }
+      });
+      ldapServer.start();
+
+      final LdapGroupsMapping mapping = new LdapGroupsMapping();
+      final Configuration conf = new Configuration();
+      conf.set(LdapGroupsMapping.LDAP_URL_KEY,
+          "ldap://localhost:" + serverSock.getLocalPort());
+      conf.setInt(CONNECTION_TIMEOUT, connectionTimeoutMs);
+      mapping.setConf(conf);
+
+      try {
+        mapping.doGetGroups("hadoop");
+        fail("The LDAP query should have timed out!");
+      } catch (NamingException ne) {
+        LOG.debug("Got the exception while LDAP querying: ", ne);
+        assertExceptionContains("LDAP response read timed out, timeout used:" +
+            connectionTimeoutMs + "ms", ne);
+        assertFalse(ne.getMessage().contains("remaining name"));
+      } finally {
+        finLatch.countDown();
+      }
+      ldapServer.join();
+    }
+  }
+
+  /**
+   * Test that if the {@link LdapGroupsMapping#READ_TIMEOUT} is set in the
+   * configuration, the LdapGroupsMapping query will timeout by this value if
+   * it does not get a LDAP response from the server.
+   *
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  @Test(timeout = 30000)
+  public void testLdapReadTimeout() throws IOException, InterruptedException {
+    final int readTimeoutMs = 4 * 1000; // 4s
+    try (ServerSocket serverSock = new ServerSocket(0)) {
+      final CountDownLatch finLatch = new CountDownLatch(1);
+
+      // Below we create a LDAP server which will accept a client request,
+      // authenticate it successfully; but it will never reply to the following
+      // query request.
+      // Client of this LDAP server is expected to get a read timeout.
+      final Thread ldapServer = new Thread(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            try (Socket clientSock = serverSock.accept()) {
+              IOUtils.skipFully(clientSock.getInputStream(), 1);
+              clientSock.getOutputStream().write(AUTHENTICATE_SUCCESS_MSG);
+              finLatch.await();
+            }
+          } catch (Exception e) {
+            e.printStackTrace();
+          }
+        }
+      });
+      ldapServer.start();
+
+      final LdapGroupsMapping mapping = new LdapGroupsMapping();
+      final Configuration conf = new Configuration();
+      conf.set(LdapGroupsMapping.LDAP_URL_KEY,
+          "ldap://localhost:" + serverSock.getLocalPort());
+      conf.setInt(READ_TIMEOUT, readTimeoutMs);
+      mapping.setConf(conf);
+
+      try {
+        mapping.doGetGroups("hadoop");
+        fail("The LDAP query should have timed out!");
+      } catch (NamingException ne) {
+        LOG.debug("Got the exception while LDAP querying: ", ne);
+        assertExceptionContains("LDAP response read timed out, timeout used:" +
+            readTimeoutMs + "ms", ne);
+        assertExceptionContains("remaining name", ne);
+      } finally {
+        finLatch.countDown();
+      }
+      ldapServer.join();
+    }
+  }
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org