hadoop-common-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject hadoop git commit: HADOOP-12617. SPNEGO authentication request to non-default realm gets default realm name inserted in target server principal. (mattf)
Date Wed, 09 Dec 2015 01:37:38 GMT
Repository: hadoop
Updated Branches:
  refs/heads/branch-2 7013f9d6c -> 472541291


HADOOP-12617. SPNEGO authentication request to non-default realm gets default realm name inserted
in target server principal. (mattf)


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

Branch: refs/heads/branch-2
Commit: 472541291bf868c792bb70bbed5400b8520ae7e0
Parents: 7013f9d
Author: mattf <mattf@apache.org>
Authored: Tue Dec 8 17:35:25 2015 -0800
Committer: mattf <mattf@apache.org>
Committed: Tue Dec 8 17:35:25 2015 -0800

----------------------------------------------------------------------
 .../authentication/util/KerberosUtil.java       | 83 ++++++++++++++++++--
 .../authentication/util/TestKerberosUtil.java   | 29 +++++--
 hadoop-common-project/hadoop-common/CHANGES.txt |  3 +
 3 files changed, 104 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/47254129/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
index f7f5f63..fec7f01 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java
@@ -83,17 +83,79 @@ public class KerberosUtil {
          new Class[0]);
     return (String)getDefaultRealmMethod.invoke(kerbConf, new Object[0]);
   }
-  
+
+  public static String getDefaultRealmProtected() {
+    String realmString = null;
+    try {
+      realmString = getDefaultRealm();
+    } catch (RuntimeException rte) {
+      //silently catch everything
+    } catch (Exception e) {
+      //silently return null
+    }
+    return realmString;
+  }
+
+  /*
+   * For a Service Host Principal specification, map the host's domain
+   * to kerberos realm, as specified by krb5.conf [domain_realm] mappings.
+   * Unfortunately the mapping routines are private to the security.krb5
+   * package, so have to construct a PrincipalName instance to derive the realm.
+   *
+   * Many things can go wrong with Kerberos configuration, and this is not
+   * the place to be throwing exceptions to help debug them.  Nor do we choose
+   * to make potentially voluminous logs on every call to a communications API.
+   * So we simply swallow all exceptions from the underlying libraries and
+   * return null if we can't get a good value for the realmString.
+   *
+   * @param shortprinc A service principal name with host fqdn as instance, e.g.
+   *     "HTTP/myhost.mydomain"
+   * @return String value of Kerberos realm, mapped from host fqdn
+   *     May be default realm, or may be null.
+   */
+  public static String getDomainRealm(String shortprinc) {
+    Class<?> classRef;
+    Object principalName; //of type sun.security.krb5.PrincipalName or IBM equiv
+    String realmString = null;
+    try {
+      if (System.getProperty("java.vendor").contains("IBM")) {
+        classRef = Class.forName("com.ibm.security.krb5.PrincipalName");
+      } else {
+        classRef = Class.forName("sun.security.krb5.PrincipalName");
+      }
+      int tKrbNtSrvHst = classRef.getField("KRB_NT_SRV_HST").getInt(null);
+      principalName = classRef.getConstructor(String.class, int.class).
+          newInstance(shortprinc, tKrbNtSrvHst);
+      realmString = (String)classRef.getMethod("getRealmString", new Class[0]).
+          invoke(principalName, new Object[0]);
+    } catch (RuntimeException rte) {
+      //silently catch everything
+    } catch (Exception e) {
+      //silently return default realm (which may itself be null)
+    }
+    if (null == realmString || realmString.equals("")) {
+      return getDefaultRealmProtected();
+    } else {
+      return realmString;
+    }
+  }
+
   /* Return fqdn of the current host */
   static String getLocalHostName() throws UnknownHostException {
     return InetAddress.getLocalHost().getCanonicalHostName();
   }
   
   /**
-   * Create Kerberos principal for a given service and hostname. It converts
+   * Create Kerberos principal for a given service and hostname,
+   * inferring realm from the fqdn of the hostname. It converts
    * hostname to lower case. If hostname is null or "0.0.0.0", it uses
    * dynamically looked-up fqdn of the current host instead.
-   * 
+   * If domain_realm mappings are inadequately specified, it will
+   * use default_realm, per usual Kerberos behavior.
+   * If default_realm also gives a null value, then a principal
+   * without realm will be returned, which by Kerberos definitions is
+   * just another way to specify default realm.
+   *
    * @param service
    *          Service for which you want to generate the principal.
    * @param hostname
@@ -102,15 +164,26 @@ public class KerberosUtil {
    * @throws UnknownHostException
    *           If no IP address for the local host could be found.
    */
-  public static final String getServicePrincipal(String service, String hostname)
+  public static final String getServicePrincipal(String service,
+      String hostname)
       throws UnknownHostException {
     String fqdn = hostname;
+    String shortprinc = null;
+    String realmString = null;
     if (null == fqdn || fqdn.equals("") || fqdn.equals("0.0.0.0")) {
       fqdn = getLocalHostName();
     }
     // convert hostname to lowercase as kerberos does not work with hostnames
     // with uppercase characters.
-    return service + "/" + fqdn.toLowerCase(Locale.ENGLISH);
+    fqdn = fqdn.toLowerCase(Locale.ENGLISH);
+    shortprinc = service + "/" + fqdn;
+    // Obtain the realm name inferred from the domain of the host
+    realmString = getDomainRealm(shortprinc);
+    if (null == realmString || realmString.equals("")) {
+      return shortprinc;
+    } else {
+      return shortprinc + "@" + realmString;
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/hadoop/blob/47254129/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
index 89e07d1..97ef025 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java
@@ -18,6 +18,7 @@ package org.apache.hadoop.security.authentication.util;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -52,30 +53,46 @@ public class TestKerberosUtil {
   }
 
   @Test
-  public void testGetServerPrincipal() throws IOException {
+  public void testGetServerPrincipal()
+      throws IOException, UnknownHostException {
     String service = "TestKerberosUtil";
     String localHostname = KerberosUtil.getLocalHostName();
     String testHost = "FooBar";
+    String defaultRealm = KerberosUtil.getDefaultRealmProtected();
+
+    String atDefaultRealm;
+    if (defaultRealm == null || defaultRealm.equals("")) {
+      atDefaultRealm = "";
+    } else {
+      atDefaultRealm = "@" + defaultRealm;
+    }
+    // check that the test environment is as expected
+    Assert.assertEquals("testGetServerPrincipal assumes localhost realm is default",
+        KerberosUtil.getDomainRealm(service + "/" + localHostname.toLowerCase(Locale.ENGLISH)),
+        defaultRealm);
+    Assert.assertEquals("testGetServerPrincipal assumes realm of testHost 'FooBar' is default",
+        KerberosUtil.getDomainRealm(service + "/" + testHost.toLowerCase(Locale.ENGLISH)),
+        defaultRealm);
 
     // send null hostname
     Assert.assertEquals("When no hostname is sent",
-        service + "/" + localHostname.toLowerCase(Locale.ENGLISH),
+        service + "/" + localHostname.toLowerCase(Locale.ENGLISH) + atDefaultRealm,
         KerberosUtil.getServicePrincipal(service, null));
     // send empty hostname
     Assert.assertEquals("When empty hostname is sent",
-        service + "/" + localHostname.toLowerCase(Locale.ENGLISH),
+        service + "/" + localHostname.toLowerCase(Locale.ENGLISH) + atDefaultRealm,
         KerberosUtil.getServicePrincipal(service, ""));
     // send 0.0.0.0 hostname
     Assert.assertEquals("When 0.0.0.0 hostname is sent",
-        service + "/" + localHostname.toLowerCase(Locale.ENGLISH),
+        service + "/" + localHostname.toLowerCase(Locale.ENGLISH) + atDefaultRealm,
         KerberosUtil.getServicePrincipal(service, "0.0.0.0"));
     // send uppercase hostname
     Assert.assertEquals("When uppercase hostname is sent",
-        service + "/" + testHost.toLowerCase(Locale.ENGLISH),
+        service + "/" + testHost.toLowerCase(Locale.ENGLISH) + atDefaultRealm,
         KerberosUtil.getServicePrincipal(service, testHost));
     // send lowercase hostname
     Assert.assertEquals("When lowercase hostname is sent",
-        service + "/" + testHost.toLowerCase(Locale.ENGLISH),
+        service + "/" + testHost.toLowerCase(Locale.ENGLISH) + atDefaultRealm,
         KerberosUtil.getServicePrincipal(
             service, testHost.toLowerCase(Locale.ENGLISH)));
   }

http://git-wip-us.apache.org/repos/asf/hadoop/blob/47254129/hadoop-common-project/hadoop-common/CHANGES.txt
----------------------------------------------------------------------
diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt
index 1b23b4e..f5cdb56 100644
--- a/hadoop-common-project/hadoop-common/CHANGES.txt
+++ b/hadoop-common-project/hadoop-common/CHANGES.txt
@@ -412,6 +412,9 @@ Release 2.8.0 - UNRELEASED
 
   BUG FIXES
 
+    HADOOP-12617. SPNEGO authentication request to non-default realm gets
+    default realm name inserted in target server principal. (mattf)
+
     HADOOP-12352. Delay in checkpointing Trash can leave trash for 2 intervals
     before deleting (Casey Brotherton via harsh)
 


Mime
View raw message