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 6a087f4022c..c9b21d1c3a1 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
@@ -37,6 +37,8 @@
import java.util.HashMap;
import java.util.Map;
+import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
+
/**
* The {@link KerberosAuthenticator} implements the Kerberos SPNEGO authentication sequence.
*
@@ -75,13 +77,29 @@ private static class KerberosConfiguration extends Configuration {
private static final String OS_LOGIN_MODULE_NAME;
private static final boolean windows = System.getProperty("os.name").startsWith("Windows");
+ private static final boolean is64Bit = System.getProperty("os.arch").contains("64");
+ private static final boolean aix = System.getProperty("os.name").equals("AIX");
+
+ /* Return the OS login module class name */
+ private static String getOSLoginModuleName() {
+ if (IBM_JAVA) {
+ if (windows) {
+ return is64Bit ? "com.ibm.security.auth.module.Win64LoginModule"
+ : "com.ibm.security.auth.module.NTLoginModule";
+ } else if (aix) {
+ return is64Bit ? "com.ibm.security.auth.module.AIX64LoginModule"
+ : "com.ibm.security.auth.module.AIXLoginModule";
+ } else {
+ return "com.ibm.security.auth.module.LinuxLoginModule";
+ }
+ } else {
+ return windows ? "com.sun.security.auth.module.NTLoginModule"
+ : "com.sun.security.auth.module.UnixLoginModule";
+ }
+ }
static {
- if (windows) {
- OS_LOGIN_MODULE_NAME = "com.sun.security.auth.module.NTLoginModule";
- } else {
- OS_LOGIN_MODULE_NAME = "com.sun.security.auth.module.UnixLoginModule";
- }
+ OS_LOGIN_MODULE_NAME = getOSLoginModuleName();
}
private static final AppConfigurationEntry OS_SPECIFIC_LOGIN =
@@ -92,13 +110,22 @@ private static class KerberosConfiguration extends Configuration {
private static final Map USER_KERBEROS_OPTIONS = new HashMap();
static {
- USER_KERBEROS_OPTIONS.put("doNotPrompt", "true");
- USER_KERBEROS_OPTIONS.put("useTicketCache", "true");
- USER_KERBEROS_OPTIONS.put("renewTGT", "true");
String ticketCache = System.getenv("KRB5CCNAME");
- if (ticketCache != null) {
- USER_KERBEROS_OPTIONS.put("ticketCache", ticketCache);
+ if (IBM_JAVA) {
+ USER_KERBEROS_OPTIONS.put("useDefaultCcache", "true");
+ } else {
+ USER_KERBEROS_OPTIONS.put("doNotPrompt", "true");
+ USER_KERBEROS_OPTIONS.put("useTicketCache", "true");
}
+ if (ticketCache != null) {
+ if (IBM_JAVA) {
+ // The first value searched when "useDefaultCcache" is used.
+ System.setProperty("KRB5CCNAME", ticketCache);
+ } else {
+ USER_KERBEROS_OPTIONS.put("ticketCache", ticketCache);
+ }
+ }
+ USER_KERBEROS_OPTIONS.put("renewTGT", "true");
}
private static final AppConfigurationEntry USER_KERBEROS_LOGIN =
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java
index 07b64f48f9f..327fc5e541f 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java
@@ -21,6 +21,7 @@
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.Oid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,6 +45,8 @@
import java.util.Properties;
import java.util.Set;
+import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
+
/**
* The {@link KerberosAuthenticationHandler} implements the Kerberos SPNEGO authentication mechanism for HTTP.
*
@@ -77,18 +80,33 @@ public KerberosConfiguration(String keytab, String principal) {
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
Map options = new HashMap();
- options.put("keyTab", keytab);
- options.put("principal", principal);
- options.put("useKeyTab", "true");
- options.put("storeKey", "true");
- options.put("doNotPrompt", "true");
- options.put("useTicketCache", "true");
- options.put("renewTGT", "true");
+ if (IBM_JAVA) {
+ options.put("useKeytab",
+ keytab.startsWith("file://") ? keytab : "file://" + keytab);
+ options.put("principal", principal);
+ options.put("credsType", "acceptor");
+ } else {
+ options.put("keyTab", keytab);
+ options.put("principal", principal);
+ options.put("useKeyTab", "true");
+ options.put("storeKey", "true");
+ options.put("doNotPrompt", "true");
+ options.put("useTicketCache", "true");
+ options.put("renewTGT", "true");
+ options.put("isInitiator", "false");
+ }
options.put("refreshKrb5Config", "true");
- options.put("isInitiator", "false");
String ticketCache = System.getenv("KRB5CCNAME");
if (ticketCache != null) {
- options.put("ticketCache", ticketCache);
+ if (IBM_JAVA) {
+ options.put("useDefaultCcache", "true");
+ // The first value searched when "useDefaultCcache" is used.
+ System.setProperty("KRB5CCNAME", ticketCache);
+ options.put("renewTGT", "true");
+ options.put("credsType", "both");
+ } else {
+ options.put("ticketCache", ticketCache);
+ }
}
if (LOG.isDebugEnabled()) {
options.put("debug", "true");
@@ -294,8 +312,18 @@ public AuthenticationToken authenticate(HttpServletRequest request, final HttpSe
public AuthenticationToken run() throws Exception {
AuthenticationToken token = null;
GSSContext gssContext = null;
+ GSSCredential gssCreds = null;
try {
- gssContext = gssManager.createContext((GSSCredential) null);
+ if (IBM_JAVA) {
+ // IBM JDK needs non-null credentials to be passed to createContext here, with
+ // SPNEGO mechanism specified, otherwise JGSS will use its default mechanism
+ // only, which is Kerberos V5.
+ gssCreds = gssManager.createCredential(null, GSSCredential.INDEFINITE_LIFETIME,
+ new Oid[]{KerberosUtil.getOidInstance("GSS_SPNEGO_MECH_OID"),
+ KerberosUtil.getOidInstance("GSS_KRB5_MECH_OID")},
+ GSSCredential.ACCEPT_ONLY);
+ }
+ gssContext = gssManager.createContext(gssCreds);
byte[] serverToken = gssContext.acceptSecContext(clientToken, 0, clientToken.length);
if (serverToken != null && serverToken.length > 0) {
String authenticate = base64.encodeToString(serverToken);
@@ -317,6 +345,9 @@ public AuthenticationToken run() throws Exception {
if (gssContext != null) {
gssContext.dispose();
}
+ if (gssCreds != null) {
+ gssCreds.dispose();
+ }
}
return token;
}
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 428435df8a8..6435e75f5e3 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
@@ -27,6 +27,8 @@
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 */
@@ -40,7 +42,11 @@ public static Oid getOidInstance(String oidName)
throws ClassNotFoundException, GSSException, NoSuchFieldException,
IllegalAccessException {
Class> oidClass;
- if (System.getProperty("java.vendor").contains("IBM")) {
+ if (IBM_JAVA) {
+ if ("NT_GSS_KRB5_PRINCIPAL".equals(oidName)) {
+ // IBM JDK GSSUtil class does not have field for krb5 principal oid
+ return new Oid("1.2.840.113554.1.2.2.1");
+ }
oidClass = Class.forName("com.ibm.security.jgss.GSSUtil");
} else {
oidClass = Class.forName("sun.security.jgss.GSSUtil");
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/PlatformName.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/util/PlatformName.java
similarity index 83%
rename from hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/PlatformName.java
rename to hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/util/PlatformName.java
index 24846f849a5..eb52839b65a 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/PlatformName.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/util/PlatformName.java
@@ -22,32 +22,33 @@
import org.apache.hadoop.classification.InterfaceStability;
/**
- * A helper class for getting build-info of the java-vm.
- *
+ * A helper class for getting build-info of the java-vm.
+ *
*/
@InterfaceAudience.LimitedPrivate({"HBase"})
@InterfaceStability.Unstable
public class PlatformName {
/**
- * The complete platform 'name' to identify the platform as
+ * The complete platform 'name' to identify the platform as
* per the java-vm.
*/
public static final String PLATFORM_NAME =
- (Shell.WINDOWS ? System.getenv("os") : System.getProperty("os.name"))
+ (System.getProperty("os.name").startsWith("Windows")
+ ? System.getenv("os") : System.getProperty("os.name"))
+ "-" + System.getProperty("os.arch")
+ "-" + System.getProperty("sun.arch.data.model");
-
+
/**
- * The java vendor name used in this platform.
+ * The java vendor name used in this platform.
*/
public static final String JAVA_VENDOR_NAME = System.getProperty("java.vendor");
/**
- * A public static variable to indicate the current java vendor is
- * IBM java or not.
+ * A public static variable to indicate the current java vendor is
+ * IBM java or not.
*/
public static final boolean IBM_JAVA = JAVA_VENDOR_NAME.contains("IBM");
-
+
public static void main(String[] args) {
System.out.println(PLATFORM_NAME);
}
diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt
index e28ef0bdd34..5b557b9a06b 100644
--- a/hadoop-common-project/hadoop-common/CHANGES.txt
+++ b/hadoop-common-project/hadoop-common/CHANGES.txt
@@ -337,6 +337,8 @@ Release 2.1.1-beta - UNRELEASED
NEW FEATURES
IMPROVEMENTS
+
+ HADOOP-9446. Support Kerberos SPNEGO for IBM JDK. (Yu Gao via llu)
HADOOP-9787. ShutdownHelper util to shutdown threads and threadpools.
(Karthik Kambatla via Sandy Ryza)
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java
index a6d5f8381f2..1594ffe0ea8 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java
@@ -439,7 +439,6 @@ private static class HadoopConfiguration
} else {
USER_KERBEROS_OPTIONS.put("doNotPrompt", "true");
USER_KERBEROS_OPTIONS.put("useTicketCache", "true");
- USER_KERBEROS_OPTIONS.put("renewTGT", "true");
}
String ticketCache = System.getenv("KRB5CCNAME");
if (ticketCache != null) {
@@ -450,6 +449,7 @@ private static class HadoopConfiguration
USER_KERBEROS_OPTIONS.put("ticketCache", ticketCache);
}
}
+ USER_KERBEROS_OPTIONS.put("renewTGT", "true");
USER_KERBEROS_OPTIONS.putAll(BASIC_JAAS_OPTIONS);
}
private static final AppConfigurationEntry USER_KERBEROS_LOGIN =
@@ -465,8 +465,8 @@ private static class HadoopConfiguration
KEYTAB_KERBEROS_OPTIONS.put("doNotPrompt", "true");
KEYTAB_KERBEROS_OPTIONS.put("useKeyTab", "true");
KEYTAB_KERBEROS_OPTIONS.put("storeKey", "true");
- KEYTAB_KERBEROS_OPTIONS.put("refreshKrb5Config", "true");
}
+ KEYTAB_KERBEROS_OPTIONS.put("refreshKrb5Config", "true");
KEYTAB_KERBEROS_OPTIONS.putAll(BASIC_JAAS_OPTIONS);
}
private static final AppConfigurationEntry KEYTAB_KERBEROS_LOGIN =
@@ -627,11 +627,17 @@ public static UserGroupInformation getUGIFromTicketCache(
}
try {
Map krbOptions = new HashMap();
- krbOptions.put("doNotPrompt", "true");
- krbOptions.put("useTicketCache", "true");
- krbOptions.put("useKeyTab", "false");
+ if (IBM_JAVA) {
+ krbOptions.put("useDefaultCcache", "true");
+ // The first value searched when "useDefaultCcache" is used.
+ System.setProperty("KRB5CCNAME", ticketCache);
+ } else {
+ krbOptions.put("doNotPrompt", "true");
+ krbOptions.put("useTicketCache", "true");
+ krbOptions.put("useKeyTab", "false");
+ krbOptions.put("ticketCache", ticketCache);
+ }
krbOptions.put("renewTGT", "false");
- krbOptions.put("ticketCache", ticketCache);
krbOptions.putAll(HadoopConfiguration.BASIC_JAAS_OPTIONS);
AppConfigurationEntry ace = new AppConfigurationEntry(
KerberosUtil.getKrb5LoginModuleName(),