@Override
    public boolean isExpired(final TicketGrantingTicketAwareTicket ticketState) {
        LOGGER.trace("Checking validity of ticket [{}]", ticketState);
        val lastTimeUsed = ticketState.getLastTimeUsed();
        val currentTime = ZonedDateTime.now(getClock());

        LOGGER.trace("Current time is [{}]. Ticket last used time is [{}]", currentTime, lastTimeUsed);

        val margin = Duration.between(lastTimeUsed, currentTime).toSeconds();
        LOGGER.trace("The duration in seconds between current time and last used time is [{}]", margin);

        if (ticketState.getCountOfUses() == 0 && margin < this.timeToKillInSeconds) {
            LOGGER.debug("Valid [{}]: Usage count is zero and number of seconds since ticket usage time [{}] is less than [{}]",
                ticketState, margin, this.timeToKillInSeconds);
            return super.isExpired(ticketState);
        }

        if (margin >= this.timeToKillInSeconds) {
            LOGGER.debug("Expired [{}]: number of seconds since ticket usage time [{}] is greater than or equal to [{}]",
                ticketState, margin, this.timeToKillInSeconds);
            return true;
        }
        if (margin > 0 && margin <= this.timeInBetweenUsesInSeconds) {
            LOGGER.warn("Expired [{}]: number of seconds since ticket usage time [{}] is less than or equal to time in between uses in seconds [{}]",
                ticketState, margin, this.timeInBetweenUsesInSeconds);
            return true;
        }

        return super.isExpired(ticketState);
    }
Implementation of an expiration policy that adds the concept of saying that a
ticket can only be used once every X milliseconds to prevent mis-configured
clients from consuming resources by doing constant redirects.

@author Scott Battaglia
@since 3.0.0
core/cas-server-core-tickets-api/src/main/java/org/apereo/cas/ticket/expiration/ThrottledUseAndTimeoutExpirationPolicy.java