Skip to content

Commit fcb80c1

Browse files
sguggilamliuml07
authored andcommitted
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>
1 parent a9ce600 commit fcb80c1

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
@@ -1233,7 +1233,29 @@ public void reloginFromKeytab() throws IOException {
12331233
reloginFromKeytab(false);
12341234
}
12351235

1236+
/**
1237+
* Force re-Login a user in from a keytab file irrespective of the last login
1238+
* time. Loads a user identity from a keytab file and logs them in. They
1239+
* become the currently logged-in user. This method assumes that
1240+
* {@link #loginUserFromKeytab(String, String)} had happened already. The
1241+
* Subject field of this UserGroupInformation object is updated to have the
1242+
* new credentials.
1243+
*
1244+
* @throws IOException
1245+
* @throws KerberosAuthException on a failure
1246+
*/
1247+
@InterfaceAudience.Public
1248+
@InterfaceStability.Evolving
1249+
public void forceReloginFromKeytab() throws IOException {
1250+
reloginFromKeytab(false, true);
1251+
}
1252+
12361253
private void reloginFromKeytab(boolean checkTGT) throws IOException {
1254+
reloginFromKeytab(checkTGT, false);
1255+
}
1256+
1257+
private void reloginFromKeytab(boolean checkTGT, boolean ignoreLastLoginTime)
1258+
throws IOException {
12371259
if (!shouldRelogin() || !isFromKeytab()) {
12381260
return;
12391261
}
@@ -1248,7 +1270,7 @@ private void reloginFromKeytab(boolean checkTGT) throws IOException {
12481270
return;
12491271
}
12501272
}
1251-
relogin(login);
1273+
relogin(login, ignoreLastLoginTime);
12521274
}
12531275

12541276
/**
@@ -1269,25 +1291,27 @@ public void reloginFromTicketCache() throws IOException {
12691291
if (login == null) {
12701292
throw new KerberosAuthException(MUST_FIRST_LOGIN);
12711293
}
1272-
relogin(login);
1294+
relogin(login, false);
12731295
}
12741296

1275-
private void relogin(HadoopLoginContext login) throws IOException {
1297+
private void relogin(HadoopLoginContext login, boolean ignoreLastLoginTime)
1298+
throws IOException {
12761299
// ensure the relogin is atomic to avoid leaving credentials in an
12771300
// inconsistent state. prevents other ugi instances, SASL, and SPNEGO
12781301
// from accessing or altering credentials during the relogin.
12791302
synchronized(login.getSubjectLock()) {
12801303
// another racing thread may have beat us to the relogin.
12811304
if (login == getLogin()) {
1282-
unprotectedRelogin(login);
1305+
unprotectedRelogin(login, ignoreLastLoginTime);
12831306
}
12841307
}
12851308
}
12861309

1287-
private void unprotectedRelogin(HadoopLoginContext login) throws IOException {
1310+
private void unprotectedRelogin(HadoopLoginContext login,
1311+
boolean ignoreLastLoginTime) throws IOException {
12881312
assert Thread.holdsLock(login.getSubjectLock());
12891313
long now = Time.now();
1290-
if (!hasSufficientTimeElapsed(now)) {
1314+
if (!hasSufficientTimeElapsed(now) && !ignoreLastLoginTime) {
12911315
return;
12921316
}
12931317
// 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
@@ -158,6 +158,42 @@ public void testUGIReLoginFromKeytab() throws Exception {
158158
Assert.assertNotSame(login1, login2);
159159
}
160160

161+
/**
162+
* Force re-login from keytab using the MiniKDC and verify the UGI can
163+
* successfully relogin from keytab as well.
164+
*/
165+
@Test
166+
public void testUGIForceReLoginFromKeytab() throws Exception {
167+
// Set this to false as we are testing force re-login anyways
168+
UserGroupInformation.setShouldRenewImmediatelyForTests(false);
169+
String principal = "foo";
170+
File keytab = new File(workDir, "foo.keytab");
171+
kdc.createPrincipal(keytab, principal);
172+
173+
UserGroupInformation.loginUserFromKeytab(principal, keytab.getPath());
174+
UserGroupInformation ugi = UserGroupInformation.getLoginUser();
175+
Assert.assertTrue("UGI should be configured to login from keytab",
176+
ugi.isFromKeytab());
177+
178+
// Verify relogin from keytab.
179+
User user = getUser(ugi.getSubject());
180+
final long firstLogin = user.getLastLogin();
181+
final LoginContext login1 = user.getLogin();
182+
Assert.assertNotNull(login1);
183+
184+
// Sleep for 2 secs to have a difference between first and second login
185+
Thread.sleep(2000);
186+
187+
// Force relogin from keytab
188+
ugi.forceReloginFromKeytab();
189+
final long secondLogin = user.getLastLogin();
190+
final LoginContext login2 = user.getLogin();
191+
Assert.assertTrue("User should have been able to relogin from keytab",
192+
secondLogin > firstLogin);
193+
Assert.assertNotNull(login2);
194+
Assert.assertNotSame(login1, login2);
195+
}
196+
161197
@Test
162198
public void testGetUGIFromKnownSubject() throws Exception {
163199
KerberosPrincipal principal = new KerberosPrincipal("user");

0 commit comments

Comments
 (0)