@Audit(
      action = "SERVICE_TICKET_VALIDATE",
      actionResolverName = "VALIDATE_SERVICE_TICKET_RESOLVER",
      resourceResolverName = "VALIDATE_SERVICE_TICKET_RESOURCE_RESOLVER")
  @Timed(name = "VALIDATE_SERVICE_TICKET_TIMER")
  @Metered(name = "VALIDATE_SERVICE_TICKET_METER")
  @Counted(name = "VALIDATE_SERVICE_TICKET_COUNTER", monotonic = true)
  @Transactional(readOnly = false)
  @Override
  public Assertion validateServiceTicket(final String serviceTicketId, final Service service)
      throws TicketException {
    final RegisteredService registeredService = this.servicesManager.findServiceBy(service);
    verifyRegisteredServiceProperties(registeredService, service);

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

    if (serviceTicket == null) {
      logger.info("Service ticket [{}] does not exist.", serviceTicketId);
      throw new InvalidTicketException(serviceTicketId);
    }

    try {
      synchronized (serviceTicket) {
        if (serviceTicket.isExpired()) {
          logger.info("ServiceTicket [{}] has expired.", serviceTicketId);
          throw new InvalidTicketException(serviceTicketId);
        }

        if (!serviceTicket.isValidFor(service)) {
          logger.error(
              "Service ticket [{}] with service [{}] does not match supplied service [{}]",
              serviceTicketId,
              serviceTicket.getService().getId(),
              service);
          throw new UnrecognizableServiceForServiceTicketValidationException(
              serviceTicket.getService());
        }
      }

      final TicketGrantingTicket root = serviceTicket.getGrantingTicket().getRoot();
      final Authentication authentication =
          getAuthenticationSatisfiedByPolicy(
              root, new ServiceContext(serviceTicket.getService(), registeredService));
      final Principal principal = authentication.getPrincipal();

      final AttributeReleasePolicy attributePolicy = registeredService.getAttributeReleasePolicy();
      logger.debug(
          "Attribute policy [{}] is associated with service [{}]",
          attributePolicy,
          registeredService);

      @SuppressWarnings("unchecked")
      final Map<String, Object> attributesToRelease =
          attributePolicy != null
              ? attributePolicy.getAttributes(principal)
              : Collections.EMPTY_MAP;

      final String principalId =
          registeredService.getUsernameAttributeProvider().resolveUsername(principal, service);
      final Principal modifiedPrincipal =
          this.principalFactory.createPrincipal(principalId, attributesToRelease);
      final AuthenticationBuilder builder = AuthenticationBuilder.newInstance(authentication);
      builder.setPrincipal(modifiedPrincipal);

      return new ImmutableAssertion(
          builder.build(),
          serviceTicket.getGrantingTicket().getChainedAuthentications(),
          serviceTicket.getService(),
          serviceTicket.isFromNewLogin());
    } finally {
      if (serviceTicket.isExpired()) {
        this.serviceTicketRegistry.deleteTicket(serviceTicketId);
      }
    }
  }