HADOOP-17159 Ability for forceful relogin in UserGroupInformation class (#2197)
Contributed by Sandeep Guggilam. Signed-off-by: Mingliang Liu <liuml07@apache.org> Signed-off-by: Steve Loughran <stevel@apache.org>
This commit is contained in:
parent
64f36b9543
commit
a932796d0c
@ -1232,7 +1232,26 @@ public void reloginFromKeytab() throws IOException {
|
|||||||
reloginFromKeytab(false);
|
reloginFromKeytab(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reloginFromKeytab(boolean checkTGT) throws IOException {
|
/**
|
||||||
|
* Force 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.
|
||||||
|
*
|
||||||
|
* @param ignoreTimeElapsed Force re-login irrespective of the time of last
|
||||||
|
* login
|
||||||
|
* @throws IOException
|
||||||
|
* @throws KerberosAuthException on a failure
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Public
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public void reloginFromKeytab(boolean ignoreTimeElapsed) throws IOException {
|
||||||
|
reloginFromKeytab(false, ignoreTimeElapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloginFromKeytab(boolean checkTGT, boolean ignoreTimeElapsed)
|
||||||
|
throws IOException {
|
||||||
if (!shouldRelogin() || !isFromKeytab()) {
|
if (!shouldRelogin() || !isFromKeytab()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1247,7 +1266,7 @@ private void reloginFromKeytab(boolean checkTGT) throws IOException {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
relogin(login);
|
relogin(login, ignoreTimeElapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1268,25 +1287,27 @@ public void reloginFromTicketCache() throws IOException {
|
|||||||
if (login == null) {
|
if (login == null) {
|
||||||
throw new KerberosAuthException(MUST_FIRST_LOGIN);
|
throw new KerberosAuthException(MUST_FIRST_LOGIN);
|
||||||
}
|
}
|
||||||
relogin(login);
|
relogin(login, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void relogin(HadoopLoginContext login) throws IOException {
|
private void relogin(HadoopLoginContext login, boolean ignoreTimeElapsed)
|
||||||
|
throws IOException {
|
||||||
// ensure the relogin is atomic to avoid leaving credentials in an
|
// ensure the relogin is atomic to avoid leaving credentials in an
|
||||||
// inconsistent state. prevents other ugi instances, SASL, and SPNEGO
|
// inconsistent state. prevents other ugi instances, SASL, and SPNEGO
|
||||||
// from accessing or altering credentials during the relogin.
|
// from accessing or altering credentials during the relogin.
|
||||||
synchronized(login.getSubjectLock()) {
|
synchronized(login.getSubjectLock()) {
|
||||||
// another racing thread may have beat us to the relogin.
|
// another racing thread may have beat us to the relogin.
|
||||||
if (login == getLogin()) {
|
if (login == getLogin()) {
|
||||||
unprotectedRelogin(login);
|
unprotectedRelogin(login, ignoreTimeElapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unprotectedRelogin(HadoopLoginContext login) throws IOException {
|
private void unprotectedRelogin(HadoopLoginContext login,
|
||||||
|
boolean ignoreTimeElapsed) throws IOException {
|
||||||
assert Thread.holdsLock(login.getSubjectLock());
|
assert Thread.holdsLock(login.getSubjectLock());
|
||||||
long now = Time.now();
|
long now = Time.now();
|
||||||
if (!hasSufficientTimeElapsed(now)) {
|
if (!hasSufficientTimeElapsed(now) && !ignoreTimeElapsed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// register most recent relogin attempt
|
// register most recent relogin attempt
|
||||||
|
@ -158,6 +158,42 @@ public void testUGIReLoginFromKeytab() throws Exception {
|
|||||||
Assert.assertNotSame(login1, login2);
|
Assert.assertNotSame(login1, login2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
// Set this to false as we are testing force re-login anyways
|
||||||
|
UserGroupInformation.setShouldRenewImmediatelyForTests(false);
|
||||||
|
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 = getUser(ugi.getSubject());
|
||||||
|
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.reloginFromKeytab(true);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetUGIFromKnownSubject() throws Exception {
|
public void testGetUGIFromKnownSubject() throws Exception {
|
||||||
KerberosPrincipal principal = new KerberosPrincipal("user");
|
KerberosPrincipal principal = new KerberosPrincipal("user");
|
||||||
|
Loading…
Reference in New Issue
Block a user