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 ki...@apache.org on 2014/04/28 15:54:49 UTC

svn commit: r1590639 - in /hadoop/common/branches/branch-2/hadoop-common-project: hadoop-auth/ hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/ hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/ hadoop-co...

Author: kihwal
Date: Mon Apr 28 13:54:48 2014
New Revision: 1590639

URL: http://svn.apache.org/r1590639
Log:
svn merge -c 1590637 merging from trunk to branch-2 to fix:HADOOP-10322. Add ability to read principal names from a keytab. Contributed by Benoy Antony and Daryn Sharp.

Modified:
    hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/pom.xml
    hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
    hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
    hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt

Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/pom.xml
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/pom.xml?rev=1590639&r1=1590638&r2=1590639&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/pom.xml (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/pom.xml Mon Apr 28 13:54:48 2014
@@ -102,6 +102,12 @@
       <artifactId>httpclient</artifactId>
       <scope>compile</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.directory.server</groupId>
+      <artifactId>apacheds-kerberos-codec</artifactId>
+      <version>2.0.0-M15</version>
+      <scope>compile</scope>
+    </dependency>
   </dependencies>
 
   <build>

Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java?rev=1590639&r1=1590638&r2=1590639&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java Mon Apr 28 13:54:48 2014
@@ -17,18 +17,27 @@
  */
 package org.apache.hadoop.security.authentication.util;
 
+import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
+
+import java.io.File;
+import java.io.IOException;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Pattern;
 
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.Oid;
 
-import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
-
 public class KerberosUtil {
 
   /* Return the Kerberos login module name */
@@ -103,4 +112,48 @@ public class KerberosUtil {
     // with uppercase characters.
     return service + "/" + fqdn.toLowerCase(Locale.US);
   }
+
+  /**
+   * Get all the unique principals present in the keytabfile.
+   * 
+   * @param keytabFileName 
+   *          Name of the keytab file to be read.
+   * @return list of unique principals in the keytab.
+   * @throws IOException 
+   *          If keytab entries cannot be read from the file.
+   */
+  static final String[] getPrincipalNames(String keytabFileName) throws IOException {
+      Keytab keytab = Keytab.read(new File(keytabFileName));
+      Set<String> principals = new HashSet<String>();
+      List<KeytabEntry> entries = keytab.getEntries();
+      for (KeytabEntry entry: entries){
+        principals.add(entry.getPrincipalName().replace("\\", "/"));
+      }
+      return principals.toArray(new String[0]);
+    }
+
+  /**
+   * Get all the unique principals from keytabfile which matches a pattern.
+   * 
+   * @param keytab 
+   *          Name of the keytab file to be read.
+   * @param pattern 
+   *         pattern to be matched.
+   * @return list of unique principals which matches the pattern.
+   * @throws IOException 
+   */
+  public static final String[] getPrincipalNames(String keytab,
+      Pattern pattern) throws IOException {
+    String[] principals = getPrincipalNames(keytab);
+    if (principals.length != 0) {
+      List<String> matchingPrincipals = new ArrayList<String>();
+      for (String principal : principals) {
+        if (pattern.matcher(principal).matches()) {
+          matchingPrincipals.add(principal);
+        }
+      }
+      principals = matchingPrincipals.toArray(new String[0]);
+    }
+    return principals;
+  }
 }

Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java?rev=1590639&r1=1590638&r2=1590639&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java Mon Apr 28 13:54:48 2014
@@ -16,13 +16,39 @@
  */
 package org.apache.hadoop.security.authentication.util;
 
-import org.junit.Assert;
-
+import java.io.File;
 import java.io.IOException;
-
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.directory.server.kerberos.shared.keytab.Keytab;
+import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
+import org.apache.directory.shared.kerberos.KerberosTime;
+import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
+import org.apache.directory.shared.kerberos.components.EncryptionKey;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class TestKerberosUtil {
+  static String testKeytab = "test.keytab";
+  static String[] testPrincipals = new String[]{
+      "HTTP@testRealm",
+      "test/testhost@testRealm",
+      "HTTP/testhost@testRealm",
+      "HTTP1/testhost@testRealm",
+      "HTTP/testhostanother@testRealm"
+  };
+
+  @After
+  public void deleteKeytab() {
+    File keytabFile = new File(testKeytab);
+    if (keytabFile.exists()){
+      keytabFile.delete();
+    }
+  }
 
   @Test
   public void testGetServerPrincipal() throws IOException {
@@ -51,4 +77,84 @@ public class TestKerberosUtil {
         service + "/" + testHost.toLowerCase(),
         KerberosUtil.getServicePrincipal(service, testHost.toLowerCase()));
   }
+  
+  @Test
+  public void testGetPrincipalNamesMissingKeytab() {
+    try {
+      KerberosUtil.getPrincipalNames(testKeytab);
+      Assert.fail("Exception should have been thrown");
+    } catch (IOException e) {
+      //expects exception
+    }
+  }
+
+  @Test
+  public void testGetPrincipalNamesMissingPattern() throws IOException {
+    createKeyTab(testKeytab, new String[]{"test/testhost@testRealm"});
+    try {
+      KerberosUtil.getPrincipalNames(testKeytab, null);
+      Assert.fail("Exception should have been thrown");
+    } catch (Exception e) {
+      //expects exception
+    }
+  }
+
+  @Test
+  public void testGetPrincipalNamesFromKeytab() throws IOException {
+    createKeyTab(testKeytab, testPrincipals); 
+    // read all principals in the keytab file
+    String[] principals = KerberosUtil.getPrincipalNames(testKeytab);
+    Assert.assertNotNull("principals cannot be null", principals);
+    
+    int expectedSize = 0;
+    List<String> principalList = Arrays.asList(principals);
+    for (String principal : testPrincipals) {
+      Assert.assertTrue("missing principal "+principal,
+          principalList.contains(principal));
+      expectedSize++;
+    }
+    Assert.assertEquals(expectedSize, principals.length);
+  }
+  
+  @Test
+  public void testGetPrincipalNamesFromKeytabWithPattern() throws IOException {
+    createKeyTab(testKeytab, testPrincipals); 
+    // read the keytab file
+    // look for principals with HTTP as the first part
+    Pattern httpPattern = Pattern.compile("HTTP/.*");
+    String[] httpPrincipals =
+        KerberosUtil.getPrincipalNames(testKeytab, httpPattern);
+    Assert.assertNotNull("principals cannot be null", httpPrincipals);
+    
+    int expectedSize = 0;
+    List<String> httpPrincipalList = Arrays.asList(httpPrincipals);
+    for (String principal : testPrincipals) {
+      if (httpPattern.matcher(principal).matches()) {
+        Assert.assertTrue("missing principal "+principal,
+            httpPrincipalList.contains(principal));
+        expectedSize++;
+      }
+    }
+    Assert.assertEquals(expectedSize, httpPrincipals.length);
+  }
+  
+  private void createKeyTab(String fileName, String[] principalNames)
+      throws IOException {
+    //create a test keytab file
+    List<KeytabEntry> lstEntries = new ArrayList<KeytabEntry>();
+    for (String principal : principalNames){
+      // create 3 versions of the key to ensure methods don't return
+      // duplicate principals
+      for (int kvno=1; kvno <= 3; kvno++) {
+        EncryptionKey key = new EncryptionKey(
+            EncryptionType.UNKNOWN, "samplekey1".getBytes(), kvno);
+        KeytabEntry keytabEntry = new KeytabEntry(
+            principal, 1 , new KerberosTime(), (byte) 1, key);
+        lstEntries.add(keytabEntry);      
+      }
+    }
+    Keytab keytab = Keytab.getInstance();
+    keytab.setEntries(lstEntries);
+    keytab.write(new File(testKeytab));
+  }
 }
\ No newline at end of file

Modified: hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt?rev=1590639&r1=1590638&r2=1590639&view=diff
==============================================================================
--- hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt (original)
+++ hadoop/common/branches/branch-2/hadoop-common-project/hadoop-common/CHANGES.txt Mon Apr 28 13:54:48 2014
@@ -30,6 +30,9 @@ Release 2.5.0 - UNRELEASED
     HADOOP-10535. Make the retry numbers in ActiveStandbyElector configurable.
     (jing9)
 
+    HADOOP-10322. Add ability to read principal names from a keytab.
+    (Benoy Antony and Daryn Sharp via kihwal)
+
   OPTIMIZATIONS
 
   BUG FIXES