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 985f60703e7..7e73befed36 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 class KerberosAuthenticator implements Authenticator { 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 5688e600f77..428435df8a8 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 @@ package org.apache.hadoop.security.authentication.util; 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 class KerberosUtil { 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 00000000000..4c91e2bf13a --- /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