@Audit(
      action = "PROXY_GRANTING_TICKET",
      actionResolverName = "GRANT_PROXY_GRANTING_TICKET_RESOLVER",
      resourceResolverName = "GRANT_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER")
  @Timed(name = "GRANT_PROXY_GRANTING_TICKET_TIMER")
  @Metered(name = "GRANT_PROXY_GRANTING_TICKET_METER")
  @Counted(name = "GRANT_PROXY_GRANTING_TICKET_COUNTER", monotonic = true)
  @Transactional(readOnly = false)
  @Override
  public TicketGrantingTicket delegateTicketGrantingTicket(
      final String serviceTicketId, final Credential... credentials)
      throws AuthenticationException, TicketException {

    final ServiceTicket serviceTicket =
        this.serviceTicketRegistry.getTicket(serviceTicketId, ServiceTicket.class);

    if (serviceTicket == null || serviceTicket.isExpired()) {
      logger.debug(
          "ServiceTicket [{}] has expired or cannot be found in the ticket registry",
          serviceTicketId);
      throw new InvalidTicketException(serviceTicketId);
    }

    final RegisteredService registeredService =
        this.servicesManager.findServiceBy(serviceTicket.getService());

    verifyRegisteredServiceProperties(registeredService, serviceTicket.getService());

    if (!registeredService.getProxyPolicy().isAllowedToProxy()) {
      logger.warn(
          "ServiceManagement: Service [{}] attempted to proxy, but is not allowed.",
          serviceTicket.getService().getId());
      throw new UnauthorizedProxyingException();
    }

    final Authentication authentication = this.authenticationManager.authenticate(credentials);

    final String pgtId =
        this.ticketGrantingTicketUniqueTicketIdGenerator.getNewTicketId(
            TicketGrantingTicket.PROXY_GRANTING_TICKET_PREFIX);
    final TicketGrantingTicket proxyGrantingTicket =
        serviceTicket.grantTicketGrantingTicket(
            pgtId, authentication, this.ticketGrantingTicketExpirationPolicy);

    logger.debug(
        "Generated proxy granting ticket [{}] based off of [{}]",
        proxyGrantingTicket,
        serviceTicketId);
    this.ticketRegistry.addTicket(proxyGrantingTicket);

    return proxyGrantingTicket;
  }
  @Audit(
      action = "PROXY_GRANTING_TICKET",
      actionResolverName = "GRANT_PROXY_GRANTING_TICKET_RESOLVER",
      resourceResolverName = "GRANT_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER")
  @Profiled(tag = "GRANT_PROXY_GRANTING_TICKET", logFailuresSeparately = false)
  @Transactional(readOnly = false)
  @Override
  public String delegateTicketGrantingTicket(
      final String serviceTicketId, final Credential... credentials)
      throws AuthenticationException, TicketException {

    Assert.notNull(serviceTicketId, "serviceTicketId cannot be null");
    Assert.notNull(credentials, "credentials cannot be null");

    final ServiceTicket serviceTicket =
        this.serviceTicketRegistry.getTicket(serviceTicketId, ServiceTicket.class);

    if (serviceTicket == null || serviceTicket.isExpired()) {
      logger.debug(
          "ServiceTicket [{}] has expired or cannot be found in the ticket registry",
          serviceTicketId);
      throw new InvalidTicketException(serviceTicketId);
    }

    final RegisteredService registeredService =
        this.servicesManager.findServiceBy(serviceTicket.getService());

    verifyRegisteredServiceProperties(registeredService, serviceTicket.getService());

    if (!registeredService.isAllowedToProxy()) {
      logger.warn(
          "ServiceManagement: Service [{}] attempted to proxy, but is not allowed.",
          serviceTicket.getService().getId());
      throw new UnauthorizedProxyingException();
    }

    final Authentication authentication = this.authenticationManager.authenticate(credentials);

    final TicketGrantingTicket ticketGrantingTicket =
        serviceTicket.grantTicketGrantingTicket(
            this.ticketGrantingTicketUniqueTicketIdGenerator.getNewTicketId(
                TicketGrantingTicket.PREFIX),
            authentication,
            this.ticketGrantingTicketExpirationPolicy);

    this.ticketRegistry.addTicket(ticketGrantingTicket);

    return ticketGrantingTicket.getId();
  }