/*
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jasig.cas;
import com.github.inspektr.audit.annotation.Audit;
import org.apache.commons.lang.StringUtils;
import org.jasig.cas.authentication.Authentication;
import org.jasig.cas.authentication.AuthenticationManager;
import org.jasig.cas.authentication.MutableAuthentication;
import org.jasig.cas.authentication.handler.AuthenticationException;
import org.jasig.cas.authentication.principal.Credentials;
import org.jasig.cas.authentication.principal.PersistentIdGenerator;
import org.jasig.cas.authentication.principal.Principal;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.authentication.principal.ShibbolethCompatiblePersistentIdGenerator;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.jasig.cas.services.RegisteredService;
import org.jasig.cas.services.ServicesManager;
import org.jasig.cas.services.UnauthorizedProxyingException;
import org.jasig.cas.services.UnauthorizedServiceException;
import org.jasig.cas.services.UnauthorizedSsoServiceException;
import org.jasig.cas.ticket.ExpirationPolicy;
import org.jasig.cas.ticket.InvalidTicketException;
import org.jasig.cas.ticket.ServiceTicket;
import org.jasig.cas.ticket.TicketCreationException;
import org.jasig.cas.ticket.TicketException;
import org.jasig.cas.ticket.TicketGrantingTicket;
import org.jasig.cas.ticket.TicketGrantingTicketImpl;
import org.jasig.cas.ticket.TicketValidationException;
import org.jasig.cas.ticket.registry.TicketRegistry;
import org.jasig.cas.util.UniqueTicketIdGenerator;
import org.jasig.cas.validation.Assertion;
import org.jasig.cas.validation.ImmutableAssertionImpl;
import org.perf4j.aop.Profiled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Concrete implementation of a CentralAuthenticationService, and also the
* central, organizing component of CAS's internal implementation.
* <p>
* This class is threadsafe.
* <p>
* This class has the following properties that must be set:
* <ul>
* <li> <code>ticketRegistry</code> - The Ticket Registry to maintain the list
* of available tickets.</li>
* <li> <code>serviceTicketRegistry</code> - Provides an alternative to configure separate registries for TGTs and ST in order to store them
* in different locations (i.e. long term memory or short-term)</li>
* <li> <code>authenticationManager</code> - The service that will handle
* authentication.</li>
* <li> <code>ticketGrantingTicketUniqueTicketIdGenerator</code> - Plug in to
* generate unique secure ids for TicketGrantingTickets.</li>
* <li> <code>serviceTicketUniqueTicketIdGenerator</code> - Plug in to
* generate unique secure ids for ServiceTickets.</li>
* <li> <code>ticketGrantingTicketExpirationPolicy</code> - The expiration
* policy for TicketGrantingTickets.</li>
* <li> <code>serviceTicketExpirationPolicy</code> - The expiration policy for
* ServiceTickets.</li>
* </ul>
*
* @author William G. Thompson, Jr.
* @author Scott Battaglia
* @author Dmitry Kopylenko
* @version $Revision: 1.16 $ $Date: 2007/04/24 18:11:36 $
* @since 3.0
*/
public final class CentralAuthenticationServiceImpl implements CentralAuthenticationService {
/** Log instance for logging events, info, warnings, errors, etc. */
private final Logger log = LoggerFactory.getLogger(this.getClass());
/** TicketRegistry for storing and retrieving tickets as needed. */
@NotNull
private TicketRegistry ticketRegistry;
/** New Ticket Registry for storing and retrieving services tickets. Can point to the same one as the ticketRegistry variable. */
@NotNull
private TicketRegistry serviceTicketRegistry;
/**
* AuthenticationManager for authenticating credentials for purposes of
* obtaining tickets.
*/
@NotNull
private AuthenticationManager authenticationManager;
/**
* UniqueTicketIdGenerator to generate ids for TicketGrantingTickets
* created.
*/
@NotNull
private UniqueTicketIdGenerator ticketGrantingTicketUniqueTicketIdGenerator;
/** Map to contain the mappings of service->UniqueTicketIdGenerators */
@NotNull
private Map<String, UniqueTicketIdGenerator> uniqueTicketIdGeneratorsForService;
/** Expiration policy for ticket granting tickets. */
@NotNull
private ExpirationPolicy ticketGrantingTicketExpirationPolicy;
/** ExpirationPolicy for Service Tickets. */
@NotNull
private ExpirationPolicy serviceTicketExpirationPolicy;
/** Implementation of Service Manager */
@NotNull
private ServicesManager servicesManager;
/** Encoder to generate PseudoIds. */
@NotNull
private PersistentIdGenerator persistentIdGenerator = new ShibbolethCompatiblePersistentIdGenerator();
/**
* Implementation of destoryTicketGrantingTicket expires the ticket provided
* and removes it from the TicketRegistry.
*
* @throws IllegalArgumentException if the TicketGrantingTicket ID is null.
*/
@Audit(
action="TICKET_GRANTING_TICKET_DESTROYED",
actionResolverName="DESTROY_TICKET_GRANTING_TICKET_RESOLVER",
resourceResolverName="DESTROY_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER")
@Profiled(tag = "DESTROY_TICKET_GRANTING_TICKET",logFailuresSeparately = false)
@Transactional(readOnly = false)
public void destroyTicketGrantingTicket(final String ticketGrantingTicketId) {
Assert.notNull(ticketGrantingTicketId);
if (log.isDebugEnabled()) {
log.debug("Removing ticket [" + ticketGrantingTicketId + "] from registry.");
}
final TicketGrantingTicket ticket = (TicketGrantingTicket) this.ticketRegistry.getTicket(ticketGrantingTicketId, TicketGrantingTicket.class);
if (ticket == null) {
return;
}
if (log.isDebugEnabled()) {
log.debug("Ticket found. Expiring and then deleting.");
}
ticket.expire();
this.ticketRegistry.deleteTicket(ticketGrantingTicketId);
}
/**
* @throws IllegalArgumentException if TicketGrantingTicket ID, Credentials
* or Service are null.
*/
@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)
public String grantServiceTicket(final String ticketGrantingTicketId, final Service service, final Credentials credentials) throws TicketException {
Assert.notNull(ticketGrantingTicketId, "ticketGrantingticketId cannot be null");
Assert.notNull(service, "service cannot be null");
final TicketGrantingTicket ticketGrantingTicket;
ticketGrantingTicket = (TicketGrantingTicket) this.ticketRegistry.getTicket(ticketGrantingTicketId, TicketGrantingTicket.class);
if (ticketGrantingTicket == null) {
throw