Skip to content

Commit a932796

Browse files
authored
HADOOP-17159 Ability for forceful relogin in UserGroupInformation class (#2197)
Contributed by Sandeep Guggilam. Signed-off-by: Mingliang Liu <[email protected]> Signed-off-by: Steve Loughran <[email protected]>
1 parent 64f36b9 commit a932796

File tree

2 files changed

+64
-7
lines changed

2 files changed

+64
-7
lines changed

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

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,26 @@ public void reloginFromKeytab() throws IOException {
12321232
reloginFromKeytab(false);
12331233
}
12341234

1235-
private void reloginFromKeytab(boolean checkTGT) throws IOException {
1235+
/**
1236+
* Force re-Login a user in from a keytab file. Loads a user identity from a
1237+
* keytab file and logs them in. They become the currently logged-in user.
1238+
* This method assumes that {@link #loginUserFromKeytab(String, String)} had
1239+
* happened already. The Subject field of this UserGroupInformation object is
1240+
* updated to have the new credentials.
1241+
*
1242+
* @param ignoreTimeElapsed Force re-login irrespective of the time of last
1243+
* login
1244+
* @throws IOException
1245+
* @throws KerberosAuthException on a failure
1246+
*/
1247+
@InterfaceAudience.Public
1248+
@InterfaceStability.Evolving
1249+
public void reloginFromKeytab(boolean ignoreTimeElapsed) throws IOException {
1250+
reloginFromKeytab(false, ignoreTimeElapsed);
1251+
}
1252+
1253+
private void reloginFromKeytab(boolean checkTGT, boolean ignoreTimeElapsed)
1254+
throws IOException {
12361255
if (!shouldRelogin() || !isFromKeytab()) {
12371256
return;
12381257
}
@@ -1247,7 +1266,7 @@ private void reloginFromKeytab(boolean checkTGT) throws IOException {
12471266
return;
12481267
}
12491268
}
1250-
relogin(login);
1269+
relogin(login, ignoreTimeElapsed);
12511270
}
12521271

12531272
/**
@@ -1268,25 +1287,27 @@ public void reloginFromTicketCache() throws IOException {
12681287
if (login == null) {
12691288
throw new KerberosAuthException(MUST_FIRST_LOGIN);
12701289
}
1271-
relogin(login);
1290+
relogin(login, false);
12721291
}
12731292

1274-
private void relogin(HadoopLoginContext login) throws IOException {
1293+
private void relogin(HadoopLoginContext login, boolean ignoreTimeElapsed)
1294+
throws IOException {
12751295
// ensure the relogin is atomic to avoid leaving credentials in an
12761296
// inconsistent state. prevents other ugi instances, SASL, and SPNEGO
12771297
// from accessing or altering credentials during the relogin.
12781298
synchronized(login.getSubjectLock()) {
12791299
// another racing thread may have beat us to the relogin.
12801300
if (login == getLogin()) {
1281-
unprotectedRelogin(login);
1301+
unprotectedRelogin(login, ignoreTimeElapsed);
12821302
}
12831303
}
12841304
}
12851305

1286-
private void unprotectedRelogin(HadoopLoginContext login) throws IOException {
1306+
private void unprotectedRelogin(HadoopLoginContext login,
1307+
boolean ignoreTimeElapsed) throws IOException {
12871308
assert Thread.holdsLock(login.getSubjectLock());
12881309
long now = Time.now();
1289-
if (!hasSufficientTimeElapsed(now)) {
1310+
if (!hasSufficientTimeElapsed(now) && !ignoreTimeElapsed) {
12901311
return;
12911312
}
12921313
// 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.reloginFromKeytab(true);
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)