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 07cd31496cd..bc8b47a509f 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 @@ -1215,15 +1215,37 @@ private void fixKerberosTicketOrder() { * Re-Login a user in from a keytab file. 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. + * 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 synchronized void reloginFromKeytab() throws IOException { + public void reloginFromKeytab() throws IOException { + 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(true); + } + + private synchronized void reloginFromKeytab(boolean ignoreTimeElapsed) + throws IOException { if (!isSecurityEnabled() || user.getAuthenticationMethod() != AuthenticationMethod.KERBEROS || !isKeytab) { @@ -1231,7 +1253,8 @@ public synchronized void reloginFromKeytab() throws IOException { } long now = Time.now(); - if (!shouldRenewImmediatelyForTests && !hasSufficientTimeElapsed(now)) { + if (!shouldRenewImmediatelyForTests && !ignoreTimeElapsed + && !hasSufficientTimeElapsed(now)) { return; } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGILoginFromKeytab.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGILoginFromKeytab.java index 66c2af46d10..0ada333248a 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGILoginFromKeytab.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGILoginFromKeytab.java @@ -31,6 +31,8 @@ import java.io.File; +import javax.security.auth.login.LoginContext; + /** * Verify UGI login from keytab. Check that the UGI is * configured to use keytab to catch regressions like @@ -115,4 +117,39 @@ public void testUGIReloginFromKeytab() throws Exception { secondLogin > firstLogin); } + /** + * 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 { + UserGroupInformation.setShouldRenewImmediatelyForTests(true); + 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 = ugi.getSubject().getPrincipals(User.class).iterator().next(); + 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); + } + }