Skip to content

Commit d8aaa8c

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

2 files changed

Lines changed: 66 additions & 6 deletions

File tree

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

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

12531275
/**
@@ -1268,25 +1290,27 @@ public void reloginFromTicketCache() throws IOException {
12681290
if (login == null) {
12691291
throw new KerberosAuthException(MUST_FIRST_LOGIN);
12701292
}
1271-
relogin(login);
1293+
relogin(login, false);
12721294
}
12731295

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

1286-
private void unprotectedRelogin(HadoopLoginContext login) throws IOException {
1309+
private void unprotectedRelogin(HadoopLoginContext login,
1310+
boolean ignoreLastLoginTime) throws IOException {
12871311
assert Thread.holdsLock(login.getSubjectLock());
12881312
long now = Time.now();
1289-
if (!hasSufficientTimeElapsed(now)) {
1313+
if (!hasSufficientTimeElapsed(now) && !ignoreLastLoginTime) {
12901314
return;
12911315
}
12921316
// 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)