HADOOP-15143. NPE due to Invalid KerberosTicket in UGI. Contributed by Mukul Kumar Singh.

(cherry picked from commit d31c9d8c49)
This commit is contained in:
Jitendra Pandey 2017-12-27 23:17:07 -08:00 committed by Wei-Chiu Chuang
parent e575406715
commit 169dacf1ee
2 changed files with 81 additions and 1 deletions

View File

@ -1253,7 +1253,10 @@ public class UserGroupInformation {
Object cred = iter.next(); Object cred = iter.next();
if (cred instanceof KerberosTicket) { if (cred instanceof KerberosTicket) {
KerberosTicket ticket = (KerberosTicket) cred; KerberosTicket ticket = (KerberosTicket) cred;
if (!ticket.getServer().getName().startsWith("krbtgt")) { if (ticket.isDestroyed() || ticket.getServer() == null) {
LOG.warn("Ticket is already destroyed, remove it.");
iter.remove();
} else if (!ticket.getServer().getName().startsWith("krbtgt")) {
LOG.warn( LOG.warn(
"The first kerberos ticket is not TGT" "The first kerberos ticket is not TGT"
+ "(the server principal is {}), remove and destroy it.", + "(the server principal is {}), remove and destroy it.",

View File

@ -155,4 +155,81 @@ public class TestFixKerberosTicketOrder extends KerberosSecurityTestcase {
.filter(t -> t.getServer().getName().startsWith(server2Protocol)) .filter(t -> t.getServer().getName().startsWith(server2Protocol))
.findAny().isPresent()); .findAny().isPresent());
} }
@Test
public void testWithDestroyedTGT() throws Exception {
UserGroupInformation ugi =
UserGroupInformation.loginUserFromKeytabAndReturnUGI(clientPrincipal,
keytabFile.getCanonicalPath());
ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
SaslClient client = Sasl.createSaslClient(
new String[] {AuthMethod.KERBEROS.getMechanismName()},
clientPrincipal, server1Protocol, host, props, null);
client.evaluateChallenge(new byte[0]);
client.dispose();
return null;
}
});
Subject subject = ugi.getSubject();
// mark the ticket as destroyed
for (KerberosTicket ticket : subject
.getPrivateCredentials(KerberosTicket.class)) {
if (ticket.getServer().getName().startsWith("krbtgt")) {
ticket.destroy();
break;
}
}
ugi.fixKerberosTicketOrder();
// verify that after fixing, the tgt ticket should be removed
assertFalse("The first ticket is not tgt",
subject.getPrivateCredentials().stream()
.filter(c -> c instanceof KerberosTicket)
.map(c -> ((KerberosTicket) c).getServer().getName()).findFirst()
.isPresent());
// should fail as we send a service ticket instead of tgt to KDC.
intercept(SaslException.class,
() -> ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
SaslClient client = Sasl.createSaslClient(
new String[] {AuthMethod.KERBEROS.getMechanismName()},
clientPrincipal, server2Protocol, host, props, null);
client.evaluateChallenge(new byte[0]);
client.dispose();
return null;
}
}));
// relogin to get a new ticket
ugi.reloginFromKeytab();
// make sure we can get new service ticket after the relogin.
ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
SaslClient client = Sasl.createSaslClient(
new String[] {AuthMethod.KERBEROS.getMechanismName()},
clientPrincipal, server2Protocol, host, props, null);
client.evaluateChallenge(new byte[0]);
client.dispose();
return null;
}
});
assertTrue("No service ticket for " + server2Protocol + " found",
subject.getPrivateCredentials(KerberosTicket.class).stream()
.filter(t -> t.getServer().getName().startsWith(server2Protocol))
.findAny().isPresent());
}
} }