8187218: GSSCredential.getRemainingLifetime() returns negative value for TTL > 24 days

Co-authored-by: Weijun Wang <weijun.wang@oracle.com>
Reviewed-by: mullan
This commit is contained in:
Prasadrao Koppula 2018-03-20 11:16:10 +05:30
parent 22c9d34be1
commit b3e5409c1d
3 changed files with 77 additions and 31 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -234,14 +234,12 @@ public class Krb5InitCredential
* @exception GSSException may be thrown * @exception GSSException may be thrown
*/ */
public int getInitLifetime() throws GSSException { public int getInitLifetime() throws GSSException {
int retVal = 0;
Date d = getEndTime(); Date d = getEndTime();
if (d == null) { if (d == null) {
return 0; return 0;
} }
retVal = (int)(d.getTime() - (new Date().getTime())); long retVal = d.getTime() - System.currentTimeMillis();
return (int)(retVal/1000);
return retVal/1000;
} }
/** /**

View File

@ -713,10 +713,10 @@ public class KDC {
/** /**
* Returns a KerberosTime. * Returns a KerberosTime.
* *
* @param offset offset from NOW in milliseconds * @param offset offset from NOW in seconds
*/ */
private static KerberosTime timeFor(long offset) { private static KerberosTime timeAfter(int offset) {
return new KerberosTime(new Date().getTime() + offset); return new KerberosTime(new Date().getTime() + offset * 1000L);
} }
/** /**
@ -832,12 +832,12 @@ public class KDC {
KerberosTime from = body.from; KerberosTime from = body.from;
KerberosTime till = body.till; KerberosTime till = body.till;
if (from == null || from.isZero()) { if (from == null || from.isZero()) {
from = timeFor(0); from = timeAfter(0);
} }
if (till == null) { if (till == null) {
throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO
} else if (till.isZero()) { } else if (till.isZero()) {
till = timeFor(1000 * DEFAULT_LIFETIME); till = timeAfter(DEFAULT_LIFETIME);
} }
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
@ -863,7 +863,7 @@ public class KDC {
} }
if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { if (body.kdcOptions.get(KDCOptions.RENEWABLE)) {
bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; bFlags[Krb5.TKT_OPTS_RENEWABLE] = true;
//renew = timeFor(1000 * 3600 * 24 * 7); //renew = timeAfter(3600 * 24 * 7);
} }
if (body.kdcOptions.get(KDCOptions.PROXIABLE)) { if (body.kdcOptions.get(KDCOptions.PROXIABLE)) {
bFlags[Krb5.TKT_OPTS_PROXIABLE] = true; bFlags[Krb5.TKT_OPTS_PROXIABLE] = true;
@ -933,7 +933,7 @@ public class KDC {
key, key,
cname, cname,
new TransitedEncoding(1, new byte[0]), // TODO new TransitedEncoding(1, new byte[0]), // TODO
timeFor(0), timeAfter(0),
from, from,
till, renewTill, till, renewTill,
body.addresses != null ? body.addresses body.addresses != null ? body.addresses
@ -952,13 +952,13 @@ public class KDC {
EncTGSRepPart enc_part = new EncTGSRepPart( EncTGSRepPart enc_part = new EncTGSRepPart(
key, key,
new LastReq(new LastReqEntry[] { new LastReq(new LastReqEntry[] {
new LastReqEntry(0, timeFor(-10000)) new LastReqEntry(0, timeAfter(-10))
}), }),
body.getNonce(), // TODO: detect replay body.getNonce(), // TODO: detect replay
timeFor(1000 * 3600 * 24), timeAfter(3600 * 24),
// Next 5 and last MUST be same with ticket // Next 5 and last MUST be same with ticket
tFlags, tFlags,
timeFor(0), timeAfter(0),
from, from,
till, renewTill, till, renewTill,
service, service,
@ -986,7 +986,7 @@ public class KDC {
+ " " +ke.returnCodeMessage()); + " " +ke.returnCodeMessage());
if (kerr == null) { if (kerr == null) {
kerr = new KRBError(null, null, null, kerr = new KRBError(null, null, null,
timeFor(0), timeAfter(0),
0, 0,
ke.returnCode(), ke.returnCode(),
body.cname, body.cname,
@ -1059,20 +1059,21 @@ public class KDC {
KerberosTime till = body.till; KerberosTime till = body.till;
KerberosTime rtime = body.rtime; KerberosTime rtime = body.rtime;
if (from == null || from.isZero()) { if (from == null || from.isZero()) {
from = timeFor(0); from = timeAfter(0);
} }
if (till == null) { if (till == null) {
throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO
} else if (till.isZero()) { } else if (till.isZero()) {
till = timeFor(1000 * DEFAULT_LIFETIME); till = timeAfter(DEFAULT_LIFETIME);
} else if (till.greaterThan(timeFor(24 * 3600 * 1000))) { } else if (till.greaterThan(timeAfter(24 * 3600))
&& System.getProperty("test.kdc.force.till") == null) {
// If till is more than 1 day later, make it renewable // If till is more than 1 day later, make it renewable
till = timeFor(1000 * DEFAULT_LIFETIME); till = timeAfter(DEFAULT_LIFETIME);
body.kdcOptions.set(KDCOptions.RENEWABLE, true); body.kdcOptions.set(KDCOptions.RENEWABLE, true);
if (rtime == null) rtime = till; if (rtime == null) rtime = till;
} }
if (rtime == null && body.kdcOptions.get(KDCOptions.RENEWABLE)) { if (rtime == null && body.kdcOptions.get(KDCOptions.RENEWABLE)) {
rtime = timeFor(1000 * DEFAULT_RENEWTIME); rtime = timeAfter(DEFAULT_RENEWTIME);
} }
//body.from //body.from
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1]; boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
@ -1088,7 +1089,7 @@ public class KDC {
} }
if (body.kdcOptions.get(KDCOptions.RENEWABLE)) { if (body.kdcOptions.get(KDCOptions.RENEWABLE)) {
bFlags[Krb5.TKT_OPTS_RENEWABLE] = true; bFlags[Krb5.TKT_OPTS_RENEWABLE] = true;
//renew = timeFor(1000 * 3600 * 24 * 7); //renew = timeAfter(3600 * 24 * 7);
} }
if (body.kdcOptions.get(KDCOptions.PROXIABLE)) { if (body.kdcOptions.get(KDCOptions.PROXIABLE)) {
bFlags[Krb5.TKT_OPTS_PROXIABLE] = true; bFlags[Krb5.TKT_OPTS_PROXIABLE] = true;
@ -1234,7 +1235,7 @@ public class KDC {
key, key,
body.cname, body.cname,
new TransitedEncoding(1, new byte[0]), new TransitedEncoding(1, new byte[0]),
timeFor(0), timeAfter(0),
from, from,
till, rtime, till, rtime,
body.addresses, body.addresses,
@ -1246,13 +1247,13 @@ public class KDC {
EncASRepPart enc_part = new EncASRepPart( EncASRepPart enc_part = new EncASRepPart(
key, key,
new LastReq(new LastReqEntry[]{ new LastReq(new LastReqEntry[]{
new LastReqEntry(0, timeFor(-10000)) new LastReqEntry(0, timeAfter(-10))
}), }),
body.getNonce(), // TODO: detect replay? body.getNonce(), // TODO: detect replay?
timeFor(1000 * 3600 * 24), timeAfter(3600 * 24),
// Next 5 and last MUST be same with ticket // Next 5 and last MUST be same with ticket
tFlags, tFlags,
timeFor(0), timeAfter(0),
from, from,
till, rtime, till, rtime,
service, service,
@ -1314,7 +1315,7 @@ public class KDC {
eData = temp.toByteArray(); eData = temp.toByteArray();
} }
kerr = new KRBError(null, null, null, kerr = new KRBError(null, null, null,
timeFor(0), timeAfter(0),
0, 0,
ke.returnCode(), ke.returnCode(),
body.cname, body.cname,

View File

@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 8131051 8194486 * @bug 8131051 8194486 8187218
* @summary KDC might issue a renewable ticket even if not requested * @summary KDC might issue a renewable ticket even if not requested
* @library /test/lib * @library /test/lib
* @compile -XDignore.symbol.file LongLife.java * @compile -XDignore.symbol.file LongLife.java
@ -31,7 +31,12 @@
* @run main/othervm -Djdk.net.hosts.file=TestHosts LongLife * @run main/othervm -Djdk.net.hosts.file=TestHosts LongLife
*/ */
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSManager;
import sun.security.krb5.Config; import sun.security.krb5.Config;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosTicket;
import java.security.PrivilegedExceptionAction;
public class LongLife { public class LongLife {
@ -39,11 +44,53 @@ public class LongLife {
OneKDC kdc = new OneKDC(null).writeJAASConf(); OneKDC kdc = new OneKDC(null).writeJAASConf();
// A lifetime 2d will make it renewable test(kdc, "10h", false, 36000, false);
test(kdc, "2d", false, KDC.DEFAULT_LIFETIME, true);
test(kdc, "2d", true, 2 * 24 * 3600, false);
// 8187218: getRemainingLifetime() is negative if lifetime
// is longer than 30 days.
test(kdc, "30d", true, 30 * 24 * 3600, false);
}
static void test(
KDC kdc,
String ticketLifetime,
boolean forceTill, // if true, KDC will not try RENEWABLE
int expectedLifeTime,
boolean expectedRenewable) throws Exception {
KDC.saveConfig(OneKDC.KRB5_CONF, kdc, KDC.saveConfig(OneKDC.KRB5_CONF, kdc,
"ticket_lifetime = 2d"); "ticket_lifetime = " + ticketLifetime);
Config.refresh(); Config.refresh();
Context.fromJAAS("client"); if (forceTill) {
System.setProperty("test.kdc.force.till", "");
} else {
System.clearProperty("test.kdc.force.till");
}
Context c = Context.fromJAAS("client");
GSSCredential cred = Subject.doAs(c.s(),
(PrivilegedExceptionAction<GSSCredential>)
()-> {
GSSManager m = GSSManager.getInstance();
return m.createCredential(GSSCredential.INITIATE_ONLY);
});
KerberosTicket tgt = c.s().getPrivateCredentials(KerberosTicket.class)
.iterator().next();
System.out.println(tgt);
int actualLifeTime = cred.getRemainingLifetime();
if (actualLifeTime < expectedLifeTime - 60
|| actualLifeTime > expectedLifeTime + 60) {
throw new Exception("actualLifeTime is " + actualLifeTime);
}
if (tgt.isRenewable() != expectedRenewable) {
throw new Exception("TGT's RENEWABLE flag is " + tgt.isRenewable());
}
} }
} }