[ 
https://issues.apache.org/jira/browse/HADOOP-12333?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14703812#comment-14703812
 ] 

john lilley commented on HADOOP-12333:
--------------------------------------

Allen, of course we don't want to divulge passwords, and we are very careful 
about how and where we persist them.  In particular, they do not come from any 
configuration file; they are input directly by the user and we turn around and 
use that to authenticate both with the OS and Kerberos.  If we persist them for 
later user (e.g. relogin) we keep them in memory using machine-locked 
encryption so they don't leak into swap files.  Given that both Windows and 
Linux have methods to authenticate directly from passwords, Hadoop is something 
of a departure.  UGI *does* support validation by password, it just does it 
poorly.  

Steve, regarding: "clients can relogin to kerberos, get new tickets/tokens", I 
don't see how to do this in our architecture.  Our clients may be across VPNs 
and completely inaccessible to the KDC.  Our server basically functions as the 
Hadoop client, even though it is a long-running service on the OS host.  When a 
customer logs in, it performs these steps:
-- Spawn a new process using CreateProcessWithLogon on Windows, or 
fork/PAM/setuid on Linux.
-- Use UGI to login the user using the login/password and obtain a ticket for 
the UGI's default user context.
All of this works just fine, although we are forced to use reflection to gain 
access to the private setLogin() method of UGI.

The thing is, we cannot simply login again in the same process to avoid ticket 
expiration.  It doesn't work.  I see that there is dedicated code in 
reloginFromKeytab() to clear out the old tokens and install new ones while 
keeping the UGI.class locked.  We need to be able to do something similar given 
the login and password.

It would be great if there were an in-process API that completely mimicked 
kinit and managed the TGT cache instead of the in-memory data of UGI.  But we 
haven't found one.  And we can't just run kinit, because it has no method to 
inject a password (assume intentionally, since there isn't a way to secure that 
as a command-line argument).

> UserGroupInformation method to log in and relogin with password
> ---------------------------------------------------------------
>
>                 Key: HADOOP-12333
>                 URL: https://issues.apache.org/jira/browse/HADOOP-12333
>             Project: Hadoop Common
>          Issue Type: Improvement
>          Components: security
>    Affects Versions: 2.6.0
>         Environment: all
>            Reporter: john lilley
>
> UserGroupInformation lacks a simple method to login using a password, and 
> also makes an important method private.  While many people seem to believe 
> that kinit should be used for passwords, it is unworkable in many cases (such 
> as when software is running as a service).
> Currently to workaround we must do all of this:
>     // create a dynamic configuration for the LoginContext
>     Map<String,String> krbOptions = new HashMap<String,String>();
>     krbOptions.put("doNotPrompt", "false");
>     krbOptions.put("useTicketCache", "false");
>     krbOptions.put("useKeyTab", "false");
>     krbOptions.put("renewTGT", "false");
>     AppConfigurationEntry ace = new AppConfigurationEntry(
>         KerberosUtil.getKrb5LoginModuleName(), 
> LoginModuleControlFlag.REQUIRED,
>         krbOptions);
>     DynamicConfiguration dynConf = new DynamicConfiguration(
>         new AppConfigurationEntry[] {ace});
>     // create LoginContext with login callback handler
>     LoginContext loginContext = 
> newLoginContext(USER_PASSWORD_LOGIN_KERBEROS_CONFIG_NAME, 
>       null, new LoginHandler(userPrincipal, password), dynConf);
>     loginContext.login();
>     // get Subject and Principal for logged in user
>     Subject loginSubject = loginContext.getSubject();
>     Set<Principal> loginPrincipals = loginSubject.getPrincipals();
>     if (loginPrincipals.isEmpty()) {
>       throw new LoginException("No login principals in loginSubject: " + 
> loginSubject);
>     }
>     String username = loginPrincipals.iterator().next().getName();
>     Principal ugiUser = newUser(username, AuthenticationMethod.KERBEROS, 
> loginContext);
>     // update Hadoop security details
>     loginSubject.getPrincipals().add(ugiUser);
>     UserGroupInformation loginUser = newUserGroupInformation(loginSubject);
>     UserGroupInformation.setLoginUser(loginUser);
>     setUGILogin(loginUser, loginContext); // do 
> loginUser.setLogin(loginContext)
>     loginUser.setAuthenticationMethod(AuthenticationMethod.KERBEROS);
> Note the method setUGILogin() uses reflection to overcome private method that 
> we need:
> private static void setUGILogin(UserGroupInformation loginUser, LoginContext 
> loginContext) 
>             throws SecurityException, NoSuchMethodException, 
> IllegalArgumentException, 
>             IllegalAccessException, InvocationTargetException 
>   {
>     Class<UserGroupInformation> cls = UserGroupInformation.class;
>     Method mtd = cls.getDeclaredMethod("setLogin", LoginContext.class);
>     mtd.setAccessible(true);
>     mtd.invoke(loginUser, loginContext);
>   }
>   
> Finally there is no method reloginFromPassword().  While we can use 
> reflection to access the private methods needed for this, it should simply be 
> supported.  
> PS: I really hope I've just missed something obvious and you can just call me 
> an idiot ;-)



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to