Skip to content

Commit 7f970e5

Browse files
sguggilamPACordonnier
authored andcommitted
HADOOP-17159. Make UGI support forceful relogin from keytab ignoring the last login time (apache#2249)
Contributed by Sandeep Guggilam. Signed-off-by: Mingliang Liu <[email protected]> Signed-off-by: Steve Loughran <[email protected]>
1 parent 1c3300a commit 7f970e5

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/UserGroupInformation.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,29 @@ public void reloginFromKeytab() throws IOException {
11071107
reloginFromKeytab(false);
11081108
}
11091109

1110+
/**
1111+
* Force re-Login a user in from a keytab file irrespective of the last login
1112+
* time. Loads a user identity from a keytab file and logs them in. They
1113+
* become the currently logged-in user. This method assumes that
1114+
* {@link #loginUserFromKeytab(String, String)} had happened already. The
1115+
* Subject field of this UserGroupInformation object is updated to have the
1116+
* new credentials.
1117+
*
1118+
* @throws IOException
1119+
* @throws KerberosAuthException on a failure
1120+
*/
1121+
@InterfaceAudience.Public
1122+
@InterfaceStability.Evolving
1123+
public void forceReloginFromKeytab() throws IOException {
1124+
reloginFromKeytab(false, true);
1125+
}
1126+
11101127
private void reloginFromKeytab(boolean checkTGT) throws IOException {
1128+
reloginFromKeytab(checkTGT, false);
1129+
}
1130+
1131+
private void reloginFromKeytab(boolean checkTGT, boolean ignoreLastLoginTime)
1132+
throws IOException {
11111133
if (!shouldRelogin() || !isFromKeytab()) {
11121134
return;
11131135
}
@@ -1122,7 +1144,7 @@ private void reloginFromKeytab(boolean checkTGT) throws IOException {
11221144
return;
11231145
}
11241146
}
1125-
relogin(login);
1147+
relogin(login, ignoreLastLoginTime);
11261148
}
11271149

11281150
/**
@@ -1143,25 +1165,27 @@ public void reloginFromTicketCache() throws IOException {
11431165
if (login == null) {
11441166
throw new KerberosAuthException(MUST_FIRST_LOGIN);
11451167
}
1146-
relogin(login);
1168+
relogin(login, false);
11471169
}
11481170

1149-
private void relogin(HadoopLoginContext login) throws IOException {
1171+
private void relogin(HadoopLoginContext login, boolean ignoreLastLoginTime)
1172+
throws IOException {
11501173
// ensure the relogin is atomic to avoid leaving credentials in an
11511174
// inconsistent state. prevents other ugi instances, SASL, and SPNEGO
11521175
// from accessing or altering credentials during the relogin.
11531176
synchronized(login.getSubjectLock()) {
11541177
// another racing thread may have beat us to the relogin.
11551178
if (login == getLogin()) {
1156-
unprotectedRelogin(login);
1179+
unprotectedRelogin(login, ignoreLastLoginTime);
11571180
}
11581181
}
11591182
}
11601183

1161-
private void unprotectedRelogin(HadoopLoginContext login) throws IOException {
1184+
private void unprotectedRelogin(HadoopLoginContext login,
1185+
boolean ignoreLastLoginTime) throws IOException {
11621186
assert Thread.holdsLock(login.getSubjectLock());
11631187
long now = Time.now();
1164-
if (!hasSufficientTimeElapsed(now)) {
1188+
if (!hasSufficientTimeElapsed(now) && !ignoreLastLoginTime) {
11651189
return;
11661190
}
11671191
// register most recent relogin attempt

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/TestUGILoginFromKeytab.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,42 @@ public void testUGILoginFromKeytab() throws Exception {
127127
Assert.assertNotSame(login1, login2);
128128
}
129129

130+
/**
131+
* Force re-login from keytab using the MiniKDC and verify the UGI can
132+
* successfully relogin from keytab as well.
133+
*/
134+
@Test
135+
public void testUGIForceReLoginFromKeytab() throws Exception {
136+
// Set this to false as we are testing force re-login anyways
137+
UserGroupInformation.setShouldRenewImmediatelyForTests(false);
138+
String principal = "foo";
139+
File keytab = new File(workDir, "foo.keytab");
140+
kdc.createPrincipal(keytab, principal);
141+
142+
UserGroupInformation.loginUserFromKeytab(principal, keytab.getPath());
143+
UserGroupInformation ugi = UserGroupInformation.getLoginUser();
144+
Assert.assertTrue("UGI should be configured to login from keytab",
145+
ugi.isFromKeytab());
146+
147+
// Verify relogin from keytab.
148+
User user = getUser(ugi.getSubject());
149+
final long firstLogin = user.getLastLogin();
150+
final LoginContext login1 = user.getLogin();
151+
Assert.assertNotNull(login1);
152+
153+
// Sleep for 2 secs to have a difference between first and second login
154+
Thread.sleep(2000);
155+
156+
// Force relogin from keytab
157+
ugi.forceReloginFromKeytab();
158+
final long secondLogin = user.getLastLogin();
159+
final LoginContext login2 = user.getLogin();
160+
Assert.assertTrue("User should have been able to relogin from keytab",
161+
secondLogin > firstLogin);
162+
Assert.assertNotNull(login2);
163+
Assert.assertNotSame(login1, login2);
164+
}
165+
130166
@Test
131167
public void testGetUGIFromKnownSubject() throws Exception {
132168
KerberosPrincipal principal = new KerberosPrincipal("user");

0 commit comments

Comments
 (0)