From bfce95d463b70c82c33b3bc2b15f7ed90eee592f Mon Sep 17 00:00:00 2001 From: Suresh Srinivas Date: Thu, 11 Oct 2012 06:30:40 +0000 Subject: [PATCH] HADOOP-8878. Uppercase namenode hostname causes hadoop dfs calls with webhdfs filesystem and fsck to fail when security is on. Contributed by Arpit Gupta. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1396922 13f79535-47bb-0310-9956-ffa450edef68 --- .../client/KerberosAuthenticator.java | 3 +- .../authentication/util/KerberosUtil.java | 32 +++++++++++ .../authentication/util/TestKerberosUtil.java | 55 +++++++++++++++++++ .../hadoop-common/CHANGES.txt | 11 +++- 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 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/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java index 89490bca98..14e8c44e51 100644 --- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java +++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java @@ -232,7 +232,8 @@ public Void run() throws Exception { GSSContext gssContext = null; try { GSSManager gssManager = GSSManager.getInstance(); - String servicePrincipal = "HTTP/" + KerberosAuthenticator.this.url.getHost(); + String servicePrincipal = KerberosUtil.getServicePrincipal("HTTP", + KerberosAuthenticator.this.url.getHost()); Oid oid = KerberosUtil.getOidInstance("NT_GSS_KRB5_PRINCIPAL"); GSSName serviceName = gssManager.createName(servicePrincipal, oid); 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 5688e600f7..428435df8a 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 @@ -20,6 +20,9 @@ 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.Locale; import org.ietf.jgss.GSSException; import org.ietf.jgss.Oid; @@ -65,4 +68,33 @@ public static String getDefaultRealm() new Class[0]); return (String)getDefaultRealmMethod.invoke(kerbConf, new Object[0]); } + + /* 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 + * hostname to lower case. If hostname is null or "0.0.0.0", it uses + * dynamically looked-up fqdn of the current host instead. + * + * @param service + * Service for which you want to generate the principal. + * @param hostname + * Fully-qualified domain name. + * @return Converted Kerberos principal name. + * @throws UnknownHostException + * If no IP address for the local host could be found. + */ + public static final String getServicePrincipal(String service, String hostname) + throws UnknownHostException { + String fqdn = hostname; + 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); + } } 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 new file mode 100644 index 0000000000..4c91e2bf13 --- /dev/null +++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestKerberosUtil.java @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.security.authentication.util; + +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.apache.hadoop.security.authentication.util.KerberosUtil; +import org.junit.Test; + +public class TestKerberosUtil { + + @Test + public void testGetServerPrincipal() throws IOException { + String service = "TestKerberosUtil"; + String localHostname = KerberosUtil.getLocalHostName(); + String testHost = "FooBar"; + + // send null hostname + assertEquals("When no hostname is sent", + service + "/" + localHostname.toLowerCase(), + KerberosUtil.getServicePrincipal(service, null)); + // send empty hostname + assertEquals("When empty hostname is sent", + service + "/" + localHostname.toLowerCase(), + KerberosUtil.getServicePrincipal(service, "")); + // send 0.0.0.0 hostname + assertEquals("When 0.0.0.0 hostname is sent", + service + "/" + localHostname.toLowerCase(), + KerberosUtil.getServicePrincipal(service, "0.0.0.0")); + // send uppercase hostname + assertEquals("When uppercase hostname is sent", + service + "/" + testHost.toLowerCase(), + KerberosUtil.getServicePrincipal(service, testHost)); + // send lowercase hostname + assertEquals("When lowercase hostname is sent", + service + "/" + testHost.toLowerCase(), + KerberosUtil.getServicePrincipal(service, testHost.toLowerCase())); + } +} \ No newline at end of file diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index ecf895f1cb..5561da5094 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -325,7 +325,16 @@ Release 2.0.3-alpha - Unreleased HADOOP-8756. Fix SEGV when libsnappy is in java.library.path but not LD_LIBRARY_PATH. (Colin Patrick McCabe via eli) - HADOOP-8881. FileBasedKeyStoresFactory initialization logging should be debug not info. (tucu) + HADOOP-8881. FileBasedKeyStoresFactory initialization logging should + be debug not info. (tucu) + + HADOOP-8913. hadoop-metrics2.properties should give units in comment + for sampling period. (Sandy Ryza via suresh) + + HADOOP-8878. Uppercase namenode hostname causes hadoop dfs calls with + webhdfs filesystem and fsck to fail when security is on. + (Arpit Gupta via suresh) + Release 2.0.2-alpha - 2012-09-07