Return-Path: X-Original-To: apmail-hadoop-common-commits-archive@www.apache.org Delivered-To: apmail-hadoop-common-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5F7EA183FF for ; Sun, 13 Dec 2015 07:27:26 +0000 (UTC) Received: (qmail 7732 invoked by uid 500); 13 Dec 2015 07:27:20 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 7593 invoked by uid 500); 13 Dec 2015 07:27:20 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: common-dev@hadoop.apache.org Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 6881 invoked by uid 99); 13 Dec 2015 07:27:20 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 13 Dec 2015 07:27:20 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 496D7DFFCD; Sun, 13 Dec 2015 07:27:20 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: asuresh@apache.org To: common-commits@hadoop.apache.org Date: Sun, 13 Dec 2015 07:27:36 -0000 Message-Id: In-Reply-To: <86a0ec04f28349c7a2a7344cda610774@git.apache.org> References: <86a0ec04f28349c7a2a7344cda610774@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [17/37] hadoop git commit: HADOOP-12617. SPNEGO authentication request to non-default realm gets default realm name inserted in target server principal. (mattf) 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/ada9c2c4 Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/ada9c2c4 Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/ada9c2c4 Branch: refs/heads/yarn-2877 Commit: ada9c2c410c15e95d0a21ea2941986195606aad8 Parents: 7e47151 Author: mattf Authored: Tue Dec 8 17:27:50 2015 -0800 Committer: mattf Committed: Tue Dec 8 17:27:50 2015 -0800 ---------------------------------------------------------------------- .../authentication/util/KerberosUtil.java | 87 ++++++++++++++++++-- .../authentication/util/TestKerberosUtil.java | 31 +++++-- hadoop-common-project/hadoop-common/CHANGES.txt | 3 + 3 files changed, 107 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hadoop/blob/ada9c2c4/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 0e8d8db..3d7b00d 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 @@ -42,7 +42,7 @@ public class KerberosUtil { /* Return the Kerberos login module name */ public static String getKrb5LoginModuleName() { - return System.getProperty("java.vendor").contains("IBM") + return (IBM_JAVA) ? "com.ibm.security.auth.module.Krb5LoginModule" : "com.sun.security.auth.module.Krb5LoginModule"; } @@ -72,7 +72,7 @@ public class KerberosUtil { Class classRef; Method getInstanceMethod; Method getDefaultRealmMethod; - if (System.getProperty("java.vendor").contains("IBM")) { + if (IBM_JAVA) { classRef = Class.forName("com.ibm.security.krb5.internal.Config"); } else { classRef = Class.forName("sun.security.krb5.Config"); @@ -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 (IBM_JAVA) { + 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.US); + fqdn = fqdn.toLowerCase(Locale.US); + 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/ada9c2c4/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..a0ae025 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,32 +53,48 @@ 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.US)), + defaultRealm); + Assert.assertEquals("testGetServerPrincipal assumes realm of testHost 'FooBar' is default", + KerberosUtil.getDomainRealm(service + "/" + testHost.toLowerCase(Locale.US)), + defaultRealm); // send null hostname Assert.assertEquals("When no hostname is sent", - service + "/" + localHostname.toLowerCase(Locale.ENGLISH), + service + "/" + localHostname.toLowerCase(Locale.US) + atDefaultRealm, KerberosUtil.getServicePrincipal(service, null)); // send empty hostname Assert.assertEquals("When empty hostname is sent", - service + "/" + localHostname.toLowerCase(Locale.ENGLISH), + service + "/" + localHostname.toLowerCase(Locale.US) + 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.US) + 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.US) + atDefaultRealm, KerberosUtil.getServicePrincipal(service, testHost)); // send lowercase hostname Assert.assertEquals("When lowercase hostname is sent", - service + "/" + testHost.toLowerCase(Locale.ENGLISH), + service + "/" + testHost.toLowerCase(Locale.US) + atDefaultRealm, KerberosUtil.getServicePrincipal( - service, testHost.toLowerCase(Locale.ENGLISH))); + service, testHost.toLowerCase(Locale.US))); } @Test http://git-wip-us.apache.org/repos/asf/hadoop/blob/ada9c2c4/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 4cd295e..0f505dd 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -264,6 +264,9 @@ Trunk (Unreleased) BUG FIXES + HADOOP-12617. SPNEGO authentication request to non-default realm gets + default realm name inserted in target server principal. (mattf) + HADOOP-11473. test-patch says "-1 overall" even when all checks are +1 (Jason Lowe via raviprak)