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 BD0D39B4D for ; Tue, 10 Jul 2012 18:28:38 +0000 (UTC) Received: (qmail 21351 invoked by uid 500); 10 Jul 2012 18:28:37 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 21296 invoked by uid 500); 10 Jul 2012 18:28:37 -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 21263 invoked by uid 99); 10 Jul 2012 18:28:37 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 10 Jul 2012 18:28:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 10 Jul 2012 18:28:34 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id B56C22388A2C; Tue, 10 Jul 2012 18:28:13 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1359824 - in /hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop: fs/CommonConfigurationKeys.java fs/FileSystem.java security/UserGroupInformation.java Date: Tue, 10 Jul 2012 18:28:13 -0000 To: common-commits@hadoop.apache.org From: atm@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120710182813.B56C22388A2C@eris.apache.org> Author: atm Date: Tue Jul 10 18:28:13 2012 New Revision: 1359824 URL: http://svn.apache.org/viewvc?rev=1359824&view=rev Log: HDFS-3568. fuse_dfs: add support for security. Contributed by Colin McCabe. Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeys.java hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeys.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeys.java?rev=1359824&r1=1359823&r2=1359824&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeys.java (original) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/CommonConfigurationKeys.java Tue Jul 10 18:28:13 2012 @@ -166,5 +166,12 @@ public class CommonConfigurationKeys ext "hadoop.http.staticuser.user"; public static final String DEFAULT_HADOOP_HTTP_STATIC_USER = "dr.who"; + + /* Path to the Kerberos ticket cache. Setting this will force + * UserGroupInformation to use only this ticket cache file when creating a + * FileSystem instance. + */ + public static final String KERBEROS_TICKET_CACHE_PATH = + "hadoop.security.kerberos.ticket.cache.path"; } Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java?rev=1359824&r1=1359823&r2=1359824&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java (original) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java Tue Jul 10 18:28:13 2012 @@ -137,12 +137,10 @@ public abstract class FileSystem extends */ public static FileSystem get(final URI uri, final Configuration conf, final String user) throws IOException, InterruptedException { - UserGroupInformation ugi; - if (user == null) { - ugi = UserGroupInformation.getCurrentUser(); - } else { - ugi = UserGroupInformation.createRemoteUser(user); - } + String ticketCachePath = + conf.get(CommonConfigurationKeys.KERBEROS_TICKET_CACHE_PATH); + UserGroupInformation ugi = + UserGroupInformation.getBestUGI(ticketCachePath, user); return ugi.doAs(new PrivilegedExceptionAction() { public FileSystem run() throws IOException { return get(uri, conf); @@ -314,12 +312,10 @@ public abstract class FileSystem extends */ public static FileSystem newInstance(final URI uri, final Configuration conf, final String user) throws IOException, InterruptedException { - UserGroupInformation ugi; - if (user == null) { - ugi = UserGroupInformation.getCurrentUser(); - } else { - ugi = UserGroupInformation.createRemoteUser(user); - } + String ticketCachePath = + conf.get(CommonConfigurationKeys.KERBEROS_TICKET_CACHE_PATH); + UserGroupInformation ugi = + UserGroupInformation.getBestUGI(ticketCachePath, user); return ugi.doAs(new PrivilegedExceptionAction() { public FileSystem run() throws IOException { return newInstance(uri,conf); Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java?rev=1359824&r1=1359823&r2=1359824&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java (original) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java Tue Jul 10 18:28:13 2012 @@ -19,6 +19,7 @@ package org.apache.hadoop.security; import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_SECURITY_AUTHENTICATION; +import java.io.File; import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.security.AccessControlContext; @@ -32,6 +33,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -453,9 +455,31 @@ public class UserGroupInformation { return null; } } - + + public static final HadoopConfiguration HADOOP_LOGIN_CONFIG = + new HadoopConfiguration(); + + /** + * Represents a javax.security configuration that is created at runtime. + */ + private static class DynamicConfiguration + extends javax.security.auth.login.Configuration { + private AppConfigurationEntry[] ace; + + DynamicConfiguration(AppConfigurationEntry[] ace) { + this.ace = ace; + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String appName) { + return ace; + } + } + private static LoginContext - newLoginContext(String appName, Subject subject) throws LoginException { + newLoginContext(String appName, Subject subject, + javax.security.auth.login.Configuration loginConf) + throws LoginException { // Temporarily switch the thread's ContextClassLoader to match this // class's classloader, so that we can properly load HadoopLoginModule // from the JAAS libraries. @@ -463,7 +487,7 @@ public class UserGroupInformation { ClassLoader oldCCL = t.getContextClassLoader(); t.setContextClassLoader(HadoopLoginModule.class.getClassLoader()); try { - return new LoginContext(appName, subject, null, new HadoopConfiguration()); + return new LoginContext(appName, subject, null, loginConf); } finally { t.setContextClassLoader(oldCCL); } @@ -516,6 +540,82 @@ public class UserGroupInformation { } /** + * Find the most appropriate UserGroupInformation to use + * + * @param ticketCachePath The Kerberos ticket cache path, or NULL + * if none is specfied + * @param user The user name, or NULL if none is specified. + * + * @return The most appropriate UserGroupInformation + */ + public static UserGroupInformation getBestUGI( + String ticketCachePath, String user) throws IOException { + if (ticketCachePath != null) { + return getUGIFromTicketCache(ticketCachePath, user); + } else if (user == null) { + return getCurrentUser(); + } else { + return createRemoteUser(user); + } + } + + /** + * Create a UserGroupInformation from a Kerberos ticket cache. + * + * @param user The principal name to load from the ticket + * cache + * @param ticketCachePath the path to the ticket cache file + * + * @throws IOException if the kerberos login fails + */ + @InterfaceAudience.Public + @InterfaceStability.Evolving + public static UserGroupInformation getUGIFromTicketCache( + String ticketCache, String user) throws IOException { + if (!isSecurityEnabled()) { + return getBestUGI(null, user); + } + try { + Map krbOptions = new HashMap(); + krbOptions.put("doNotPrompt", "true"); + krbOptions.put("useTicketCache", "true"); + krbOptions.put("useKeyTab", "false"); + krbOptions.put("renewTGT", "false"); + krbOptions.put("ticketCache", ticketCache); + krbOptions.putAll(HadoopConfiguration.BASIC_JAAS_OPTIONS); + AppConfigurationEntry ace = new AppConfigurationEntry( + KerberosUtil.getKrb5LoginModuleName(), + LoginModuleControlFlag.REQUIRED, + krbOptions); + DynamicConfiguration dynConf = + new DynamicConfiguration(new AppConfigurationEntry[]{ ace }); + LoginContext login = newLoginContext( + HadoopConfiguration.USER_KERBEROS_CONFIG_NAME, null, dynConf); + login.login(); + + Subject loginSubject = login.getSubject(); + Set loginPrincipals = loginSubject.getPrincipals(); + if (loginPrincipals.isEmpty()) { + throw new RuntimeException("No login principals found!"); + } + if (loginPrincipals.size() != 1) { + LOG.warn("found more than one principal in the ticket cache file " + + ticketCache); + } + User ugiUser = new User(loginPrincipals.iterator().next().getName(), + AuthenticationMethod.KERBEROS, login); + loginSubject.getPrincipals().add(ugiUser); + UserGroupInformation ugi = new UserGroupInformation(loginSubject); + ugi.setLogin(login); + ugi.setAuthenticationMethod(AuthenticationMethod.KERBEROS); + return ugi; + } catch (LoginException le) { + throw new IOException("failure to login using ticket cache file " + + ticketCache, le); + } + } + + /** * Get the currently logged in user. * @return the logged in user * @throws IOException if login fails @@ -530,10 +630,10 @@ public class UserGroupInformation { LoginContext login; if (isSecurityEnabled()) { login = newLoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME, - subject); + subject, HADOOP_LOGIN_CONFIG); } else { login = newLoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME, - subject); + subject, HADOOP_LOGIN_CONFIG); } login.login(); loginUser = new UserGroupInformation(subject); @@ -673,8 +773,8 @@ public class UserGroupInformation { LoginContext login; long start = 0; try { - login = - newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject); + login = newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, + subject, HADOOP_LOGIN_CONFIG); start = System.currentTimeMillis(); login.login(); metrics.loginSuccess.add(System.currentTimeMillis() - start); @@ -756,7 +856,8 @@ public class UserGroupInformation { // login and also update the subject field of this instance to // have the new credentials (pass it to the LoginContext constructor) login = newLoginContext( - HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, getSubject()); + HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, getSubject(), + HADOOP_LOGIN_CONFIG); LOG.info("Initiating re-login for " + keytabPrincipal); start = System.currentTimeMillis(); login.login(); @@ -807,7 +908,7 @@ public class UserGroupInformation { //have the new credentials (pass it to the LoginContext constructor) login = newLoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME, - getSubject()); + getSubject(), HADOOP_LOGIN_CONFIG); LOG.info("Initiating re-login for " + getUserName()); login.login(); setLogin(login); @@ -842,8 +943,9 @@ public class UserGroupInformation { keytabPrincipal = user; Subject subject = new Subject(); - LoginContext login = - newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject); + LoginContext login = newLoginContext( + HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject, + HADOOP_LOGIN_CONFIG); start = System.currentTimeMillis(); login.login();