8187218: GSSCredential.getRemainingLifetime() returns negative value for TTL > 24 days.
authorpkoppula
Tue, 20 Mar 2018 11:16:10 +0530
changeset 50750 45511dcfed3f
parent 50749 41a5b2de5ad3
child 50751 d9132bdf6c30
8187218: GSSCredential.getRemainingLifetime() returns negative value for TTL > 24 days. Reviewed-by: mullan Contributed-by: prasadarao.koppula@oracle.com, weijun.wang@oracle.com
src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
test/jdk/sun/security/krb5/auto/KDC.java
test/jdk/sun/security/krb5/auto/LongLife.java
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java	Mon Jun 25 10:54:55 2018 +0200
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java	Tue Mar 20 11:16:10 2018 +0530
@@ -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.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -234,14 +234,12 @@
      * @exception GSSException may be thrown
      */
     public int getInitLifetime() throws GSSException {
-        int retVal = 0;
         Date d = getEndTime();
         if (d == null) {
             return 0;
         }
-        retVal = (int)(d.getTime() - (new Date().getTime()));
-
-        return retVal/1000;
+        long retVal = d.getTime() - System.currentTimeMillis();
+        return (int)(retVal/1000);
     }
 
     /**
--- a/test/jdk/sun/security/krb5/auto/KDC.java	Mon Jun 25 10:54:55 2018 +0200
+++ b/test/jdk/sun/security/krb5/auto/KDC.java	Tue Mar 20 11:16:10 2018 +0530
@@ -713,10 +713,10 @@
     /**
      * Returns a KerberosTime.
      *
-     * @param offset offset from NOW in milliseconds
+     * @param offset offset from NOW in seconds
      */
-    private static KerberosTime timeFor(long offset) {
-        return new KerberosTime(new Date().getTime() + offset);
+    private static KerberosTime timeAfter(int offset) {
+        return new KerberosTime(new Date().getTime() + offset * 1000L);
     }
 
     /**
@@ -832,12 +832,12 @@
             KerberosTime from = body.from;
             KerberosTime till = body.till;
             if (from == null || from.isZero()) {
-                from = timeFor(0);
+                from = timeAfter(0);
             }
             if (till == null) {
                 throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO
             } else if (till.isZero()) {
-                till = timeFor(1000 * DEFAULT_LIFETIME);
+                till = timeAfter(DEFAULT_LIFETIME);
             }
 
             boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
@@ -863,7 +863,7 @@
             }
             if (body.kdcOptions.get(KDCOptions.RENEWABLE)) {
                 bFlags[Krb5.TKT_OPTS_RENEWABLE] = true;
-                //renew = timeFor(1000 * 3600 * 24 * 7);
+                //renew = timeAfter(3600 * 24 * 7);
             }
             if (body.kdcOptions.get(KDCOptions.PROXIABLE)) {
                 bFlags[Krb5.TKT_OPTS_PROXIABLE] = true;
@@ -933,7 +933,7 @@
                     key,
                     cname,
                     new TransitedEncoding(1, new byte[0]),  // TODO
-                    timeFor(0),
+                    timeAfter(0),
                     from,
                     till, renewTill,
                     body.addresses != null ? body.addresses
@@ -952,13 +952,13 @@
             EncTGSRepPart enc_part = new EncTGSRepPart(
                     key,
                     new LastReq(new LastReqEntry[] {
-                        new LastReqEntry(0, timeFor(-10000))
+                        new LastReqEntry(0, timeAfter(-10))
                     }),
                     body.getNonce(),    // TODO: detect replay
-                    timeFor(1000 * 3600 * 24),
+                    timeAfter(3600 * 24),
                     // Next 5 and last MUST be same with ticket
                     tFlags,
-                    timeFor(0),
+                    timeAfter(0),
                     from,
                     till, renewTill,
                     service,
@@ -986,7 +986,7 @@
                     + " " +ke.returnCodeMessage());
             if (kerr == null) {
                 kerr = new KRBError(null, null, null,
-                        timeFor(0),
+                        timeAfter(0),
                         0,
                         ke.returnCode(),
                         body.cname,
@@ -1059,20 +1059,21 @@
             KerberosTime till = body.till;
             KerberosTime rtime = body.rtime;
             if (from == null || from.isZero()) {
-                from = timeFor(0);
+                from = timeAfter(0);
             }
             if (till == null) {
                 throw new KrbException(Krb5.KDC_ERR_NEVER_VALID); // TODO
             } else if (till.isZero()) {
-                till = timeFor(1000 * DEFAULT_LIFETIME);
-            } else if (till.greaterThan(timeFor(24 * 3600 * 1000))) {
+                till = timeAfter(DEFAULT_LIFETIME);
+            } 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
-                till = timeFor(1000 * DEFAULT_LIFETIME);
+                till = timeAfter(DEFAULT_LIFETIME);
                 body.kdcOptions.set(KDCOptions.RENEWABLE, true);
                 if (rtime == null) rtime = till;
             }
             if (rtime == null && body.kdcOptions.get(KDCOptions.RENEWABLE)) {
-                rtime = timeFor(1000 * DEFAULT_RENEWTIME);
+                rtime = timeAfter(DEFAULT_RENEWTIME);
             }
             //body.from
             boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
@@ -1088,7 +1089,7 @@
             }
             if (body.kdcOptions.get(KDCOptions.RENEWABLE)) {
                 bFlags[Krb5.TKT_OPTS_RENEWABLE] = true;
-                //renew = timeFor(1000 * 3600 * 24 * 7);
+                //renew = timeAfter(3600 * 24 * 7);
             }
             if (body.kdcOptions.get(KDCOptions.PROXIABLE)) {
                 bFlags[Krb5.TKT_OPTS_PROXIABLE] = true;
@@ -1234,7 +1235,7 @@
                     key,
                     body.cname,
                     new TransitedEncoding(1, new byte[0]),
-                    timeFor(0),
+                    timeAfter(0),
                     from,
                     till, rtime,
                     body.addresses,
@@ -1246,13 +1247,13 @@
             EncASRepPart enc_part = new EncASRepPart(
                     key,
                     new LastReq(new LastReqEntry[]{
-                        new LastReqEntry(0, timeFor(-10000))
+                        new LastReqEntry(0, timeAfter(-10))
                     }),
                     body.getNonce(),    // TODO: detect replay?
-                    timeFor(1000 * 3600 * 24),
+                    timeAfter(3600 * 24),
                     // Next 5 and last MUST be same with ticket
                     tFlags,
-                    timeFor(0),
+                    timeAfter(0),
                     from,
                     till, rtime,
                     service,
@@ -1314,7 +1315,7 @@
                     eData = temp.toByteArray();
                 }
                 kerr = new KRBError(null, null, null,
-                        timeFor(0),
+                        timeAfter(0),
                         0,
                         ke.returnCode(),
                         body.cname,
--- a/test/jdk/sun/security/krb5/auto/LongLife.java	Mon Jun 25 10:54:55 2018 +0200
+++ b/test/jdk/sun/security/krb5/auto/LongLife.java	Tue Mar 20 11:16:10 2018 +0530
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8131051 8194486
+ * @bug 8131051 8194486 8187218
  * @summary KDC might issue a renewable ticket even if not requested
  * @library /test/lib
  * @compile -XDignore.symbol.file LongLife.java
@@ -31,7 +31,12 @@
  * @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 javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+import java.security.PrivilegedExceptionAction;
 
 public class LongLife {
 
@@ -39,11 +44,53 @@
 
         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,
-                "ticket_lifetime = 2d");
+                "ticket_lifetime = " + ticketLifetime);
         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());
+        }
     }
 }