[
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)