Duplicate :
|
|
Relates :
|
In Krb5LoginModule, when using the native ticket cache (useTicketCache=true) with the renewal option enabled (renewTGT=true), the module will attempt to renew a renewable TGT. The method Krb5LoginModule#isCurrent(...) is used to decide whether to trigger the renewal request (renewTGT=true) or ignore that ticket (with a debug message) and proceed with other authentication options when (renewTGT=false). The check in isCurrent() is correct according to its name - it checks whether the ticket has expired or not, that is, whether our current time is beyond the ticket end time: private boolean isCurrent(Credentials creds) { Date endTime = creds.getEndTime(); if (endTime != null) { return (System.currentTimeMillis() <= endTime.getTime()); } return true; } However, according to RFC4120 [1] "The Kerberos Network Authentication Service (V5)", section 2.3 "Renewable Tickets": <rfc1420> Renewable tickets have two "expiration times": the first is when the current instance of the ticket expires, and the second is the latest permissible value for an individual expiration time. An application client must periodically (i.e., before it expires) present a renewable ticket to the KDC, with the RENEW option set in the KDC request. </rfc1420> That is, expired tickets cannot be renewed, regardless of the renewable period. A ticket is renewable provided that we are within its (fixed) renewable period, AND the ticket has not already expired. For example, a TGT may be issued with validity from now and an expiry 24 hours hence, and with a renewable period of 30 days. The ticket can be renewed each day for 30 days, but it must be renewed at least once per day, otherwise it will expire. Expired tickets cannot be renewed. See also the comment for "kinit -R": -R requests renewal of the ticket-granting ticket. Note that an expired ticket cannot be renewed, even if the ticket is still within its renewable life. The above logic would appear to be oblivious to this logic (it does not attempt to renew until it thinks the ticket has expired), and therefore should never work, or very rarely at best when renewed at exactly the right time, and you would think that this would be an easily spotted problem. In fact ticket-renewal will succeed for a period after the ticket expires, due to client/KDC allowances for clock-skew, as configured in krb5.conf variable "clockskew", which defaults to 300 (seconds, or 5 minutes). So someone testing this code, who attempts to renew a ticket-cache ticket that has technically expired (but recently), will see it renew successfully due to clock-skew allowances. . This logic is problematic for the following reasons, as we rely on the clockskew setting (which we don't control and is not visible) for a grace period to renew an otherwise already expired ticket (which is not normally allowed). In the above example, we have a 24 hour period each day in the month to renew the TGT, but we rely on whatever clockskew is set (default 5 minutes), so the success window for this is reduced to that period. . The correct logic would be to divide the ticket-lifetime (endTime - startTime), multiply it by a (fixed?) renew threshold, say half-way or 0.5 (after 12h per example), and then compare the currentTimeMillis() to that time, and if we are more than half-way expired, trigger the renewal. This is a standard Kerberos approach to deal with issues such as KDC outages or infrequent inspection of the current TGT (idle application sessions). [1] http://www.ietf.org/rfc/rfc4120.txt