@Audit( action = "SERVICE_TICKET", actionResolverName = "GRANT_SERVICE_TICKET_RESOLVER", resourceResolverName = "GRANT_SERVICE_TICKET_RESOURCE_RESOLVER") @Profiled(tag = "GRANT_SERVICE_TICKET", logFailuresSeparately = false) @Transactional(readOnly = false) @Override public String grantServiceTicket( final String ticketGrantingTicketId, final Service service, final Credential... credentials) throws AuthenticationException, TicketException { Assert.notNull(ticketGrantingTicketId, "ticketGrantingticketId cannot be null"); Assert.notNull(service, "service cannot be null"); final TicketGrantingTicket ticketGrantingTicket = this.ticketRegistry.getTicket(ticketGrantingTicketId, TicketGrantingTicket.class); if (ticketGrantingTicket == null) { logger.debug( "TicketGrantingTicket [{}] cannot be found in the ticket registry.", ticketGrantingTicketId); throw new InvalidTicketException(ticketGrantingTicketId); } synchronized (ticketGrantingTicket) { if (ticketGrantingTicket.isExpired()) { this.ticketRegistry.deleteTicket(ticketGrantingTicketId); logger.debug( "TicketGrantingTicket[{}] has expired and is now deleted from the ticket registry.", ticketGrantingTicketId); throw new InvalidTicketException(ticketGrantingTicketId); } } final RegisteredService registeredService = this.servicesManager.findServiceBy(service); verifyRegisteredServiceProperties(registeredService, service); if (!registeredService.isSsoEnabled() && credentials == null && ticketGrantingTicket.getCountOfUses() > 0) { logger.warn("ServiceManagement: Service [{}] is not allowed to use SSO.", service.getId()); throw new UnauthorizedSsoServiceException(); } // CAS-1019 final List<Authentication> authns = ticketGrantingTicket.getChainedAuthentications(); if (authns.size() > 1) { if (!registeredService.isAllowedToProxy()) { final String message = String.format( "ServiceManagement: Proxy attempt by service [%s] (registered service [%s]) is not allowed.", service.getId(), registeredService.toString()); logger.warn(message); throw new UnauthorizedProxyingException(message); } } if (credentials != null) { final Authentication current = this.authenticationManager.authenticate(credentials); final Authentication original = ticketGrantingTicket.getAuthentication(); if (!current.getPrincipal().equals(original.getPrincipal())) { throw new MixedPrincipalException(current, current.getPrincipal(), original.getPrincipal()); } ticketGrantingTicket.getSupplementalAuthentications().add(current); } // Perform security policy check by getting the authentication that satisfies the configured // policy // This throws if no suitable policy is found getAuthenticationSatisfiedByPolicy( ticketGrantingTicket, new ServiceContext(service, registeredService)); final String uniqueTicketIdGenKey = service.getClass().getName(); if (!this.uniqueTicketIdGeneratorsForService.containsKey(uniqueTicketIdGenKey)) { logger.warn( "Cannot create service ticket because the key [{}] for service [{}] is not linked to a ticket id generator", uniqueTicketIdGenKey, service.getId()); throw new UnauthorizedSsoServiceException(); } final UniqueTicketIdGenerator serviceTicketUniqueTicketIdGenerator = this.uniqueTicketIdGeneratorsForService.get(uniqueTicketIdGenKey); final String generatedServiceTicketId = serviceTicketUniqueTicketIdGenerator.getNewTicketId(ServiceTicket.PREFIX); logger.debug( "Generated service ticket id [{}] for ticket granting ticket [{}]", generatedServiceTicketId, ticketGrantingTicket.getId()); final ServiceTicket serviceTicket = ticketGrantingTicket.grantServiceTicket( generatedServiceTicketId, service, this.serviceTicketExpirationPolicy, credentials != null); this.serviceTicketRegistry.addTicket(serviceTicket); if (logger.isInfoEnabled()) { final List<Authentication> authentications = serviceTicket.getGrantingTicket().getChainedAuthentications(); final String formatString = "Granted %s ticket [%s] for service [%s] for user [%s]"; final String type; final String principalId = authentications.get(authentications.size() - 1).getPrincipal().getId(); if (authentications.size() == 1) { type = "service"; } else { type = "proxy"; } logger.info( String.format(formatString, type, serviceTicket.getId(), service.getId(), principalId)); } return serviceTicket.getId(); }