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(),