@Override
    public ProxyGrantingTicket grantProxyGrantingTicket(
        final @NonNull String id, final @NonNull Authentication authentication,
        final ExpirationPolicy expirationPolicy) throws AbstractTicketException {
        if (this.grantedTicketAlready) {
            LOGGER.warn("Service ticket [{}] issued for service [{}] has already allotted a proxy-granting ticket", getId(), service.getId());
            throw new InvalidProxyGrantingTicketForServiceTicketException(service);
        }
        this.grantedTicketAlready = Boolean.TRUE;
        val proxyGrantingTicket = new ProxyGrantingTicketImpl(id, service, ticketGrantingTicket, authentication, expirationPolicy);
        proxyGrantingTicket.setTenantId(service.getTenant());
        if (ticketGrantingTicket != null) {
            ticketGrantingTicket.getProxyGrantingTickets().put(proxyGrantingTicket.getId(), service);
        }
        return proxyGrantingTicket;
    }
Domain object representing a Service Ticket. A service ticket grants specific
access to a particular service. It will only work for a particular service.
Generally, it is a one time use Ticket, but the specific expiration policy
can be anything.

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