HADOOP-17159. Make UGI support forceful relogin from keytab ignoring the last login time (#2249)

Contributed by Sandeep Guggilam.

Signed-off-by: Mingliang Liu <liuml07@apache.org>
Signed-off-by: Steve Loughran <stevel@apache.org>
This commit is contained in:
sguggilam 2020-08-26 23:45:21 -07:00 committed by GitHub
parent 2ffe00fc46
commit d8aaa8c338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 6 deletions

View File

@ -1232,7 +1232,29 @@ public class UserGroupInformation {
reloginFromKeytab(false); reloginFromKeytab(false);
} }
/**
* Force re-Login a user in from a keytab file irrespective of the last login
* time. Loads a user identity from a keytab file and logs them in. They
* become the currently logged-in user. This method assumes that
* {@link #loginUserFromKeytab(String, String)} had happened already. The
* Subject field of this UserGroupInformation object is updated to have the
* new credentials.
*
* @throws IOException
* @throws KerberosAuthException on a failure
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public void forceReloginFromKeytab() throws IOException {
reloginFromKeytab(false, true);
}
private void reloginFromKeytab(boolean checkTGT) throws IOException { private void reloginFromKeytab(boolean checkTGT) throws IOException {
reloginFromKeytab(checkTGT, false);
}
private void reloginFromKeytab(boolean checkTGT, boolean ignoreLastLoginTime)
throws IOException {
if (!shouldRelogin() || !isFromKeytab()) { if (!shouldRelogin() || !isFromKeytab()) {
return; return;
} }
@ -1247,7 +1269,7 @@ public class UserGroupInformation {
return; return;
} }
} }
relogin(login); relogin(login, ignoreLastLoginTime);
} }
/** /**
@ -1268,25 +1290,27 @@ public class UserGroupInformation {
if (login == null) { if (login == null) {
throw new KerberosAuthException(MUST_FIRST_LOGIN); throw new KerberosAuthException(MUST_FIRST_LOGIN);
} }
relogin(login); relogin(login, false);
} }
private void relogin(HadoopLoginContext login) throws IOException { private void relogin(HadoopLoginContext login, boolean ignoreLastLoginTime)
throws IOException {
// ensure the relogin is atomic to avoid leaving credentials in an // ensure the relogin is atomic to avoid leaving credentials in an
// inconsistent state. prevents other ugi instances, SASL, and SPNEGO // inconsistent state. prevents other ugi instances, SASL, and SPNEGO
// from accessing or altering credentials during the relogin. // from accessing or altering credentials during the relogin.
synchronized(login.getSubjectLock()) { synchronized(login.getSubjectLock()) {
// another racing thread may have beat us to the relogin. // another racing thread may have beat us to the relogin.
if (login == getLogin()) { if (login == getLogin()) {
unprotectedRelogin(login); unprotectedRelogin(login, ignoreLastLoginTime);
} }
} }
} }
private void unprotectedRelogin(HadoopLoginContext login) throws IOException { private void unprotectedRelogin(HadoopLoginContext login,
boolean ignoreLastLoginTime) throws IOException {
assert Thread.holdsLock(login.getSubjectLock()); assert Thread.holdsLock(login.getSubjectLock());
long now = Time.now(); long now = Time.now();
if (!hasSufficientTimeElapsed(now)) { if (!hasSufficientTimeElapsed(now) && !ignoreLastLoginTime) {
return; return;
} }
// register most recent relogin attempt // register most recent relogin attempt

View File

@ -158,6 +158,42 @@ public class TestUGILoginFromKeytab {
Assert.assertNotSame(login1, login2); Assert.assertNotSame(login1, login2);
} }
/**
* Force re-login from keytab using the MiniKDC and verify the UGI can
* successfully relogin from keytab as well.
*/
@Test
public void testUGIForceReLoginFromKeytab() throws Exception {
// Set this to false as we are testing force re-login anyways
UserGroupInformation.setShouldRenewImmediatelyForTests(false);
String principal = "foo";
File keytab = new File(workDir, "foo.keytab");
kdc.createPrincipal(keytab, principal);
UserGroupInformation.loginUserFromKeytab(principal, keytab.getPath());
UserGroupInformation ugi = UserGroupInformation.getLoginUser();
Assert.assertTrue("UGI should be configured to login from keytab",
ugi.isFromKeytab());
// Verify relogin from keytab.
User user = getUser(ugi.getSubject());
final long firstLogin = user.getLastLogin();
final LoginContext login1 = user.getLogin();
Assert.assertNotNull(login1);
// Sleep for 2 secs to have a difference between first and second login
Thread.sleep(2000);
// Force relogin from keytab
ugi.forceReloginFromKeytab();
final long secondLogin = user.getLastLogin();
final LoginContext login2 = user.getLogin();
Assert.assertTrue("User should have been able to relogin from keytab",
secondLogin > firstLogin);
Assert.assertNotNull(login2);
Assert.assertNotSame(login1, login2);
}
@Test @Test
public void testGetUGIFromKnownSubject() throws Exception { public void testGetUGIFromKnownSubject() throws Exception {
KerberosPrincipal principal = new KerberosPrincipal("user"); KerberosPrincipal principal = new KerberosPrincipal("user");