package org.apereo.cas.web; import org.apache.commons.lang3.StringEscapeUtils; import org.apereo.cas.CasProtocolConstants; import org.apereo.cas.CentralAuthenticationService; import org.apereo.cas.authentication.principal.Service; import org.apereo.cas.authentication.principal.ServiceFactory; import org.apereo.cas.authentication.principal.WebApplicationService; import org.apereo.cas.services.UnauthorizedServiceException; import org.apereo.cas.ticket.AbstractTicketException; import org.apereo.cas.ticket.proxy.ProxyTicket; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * The ProxyController is involved with returning a Proxy Ticket (in CAS 2 * terms) to the calling application. In CAS 3, a Proxy Ticket is just a Service * Ticket granted to a service. * <p> * The ProxyController requires the following property to be set: * </p> * <ul> * <li> centralAuthenticationService - the service layer</li> * <li> casArgumentExtractor - the assistant for extracting parameters</li> * </ul> * * @author Scott Battaglia * @since 3.0.0 */ public class ProxyController extends AbstractDelegateController { /** * View for if the creation of a "Proxy" Ticket Fails. */ private static final String CONST_PROXY_FAILURE = "cas2ProxyFailureView"; /** * View for if the creation of a "Proxy" Ticket Succeeds. */ private static final String CONST_PROXY_SUCCESS = "cas2ProxySuccessView"; /** * Key to use in model for service tickets. */ private static final String MODEL_SERVICE_TICKET = "ticket"; private final CentralAuthenticationService centralAuthenticationService; private final ServiceFactory webApplicationServiceFactory; @Autowired private ApplicationContext context; /** * Instantiates a new proxy controller, with cache seconds set to 0. * * @param centralAuthenticationService the central authentication service * @param webApplicationServiceFactory the web application service factory */ public ProxyController(final CentralAuthenticationService centralAuthenticationService, final ServiceFactory<WebApplicationService> webApplicationServiceFactory) { this.centralAuthenticationService = centralAuthenticationService; this.webApplicationServiceFactory = webApplicationServiceFactory; } @Override public boolean canHandle(final HttpServletRequest request, final HttpServletResponse response) { final String proxyGrantingTicket = request.getParameter(CasProtocolConstants.PARAMETER_PROXY_GRANTING_TICKET); final Service targetService = getTargetService(request); return StringUtils.hasText(proxyGrantingTicket) && targetService != null; } /** * Handle request internal. * * @param request the request * @param response the response * @return ModelAndView containing a view name of either * {@code casProxyFailureView} or {@code casProxySuccessView} */ @GetMapping(path = "/proxy") protected ModelAndView handleRequestInternal(final HttpServletRequest request, final HttpServletResponse response) { final String proxyGrantingTicket = request.getParameter(CasProtocolConstants.PARAMETER_PROXY_GRANTING_TICKET); final Service targetService = getTargetService(request); if (!StringUtils.hasText(proxyGrantingTicket) || targetService == null) { return generateErrorView(CasProtocolConstants.ERROR_CODE_INVALID_REQUEST_PROXY, null, request); } try { final ProxyTicket proxyTicket = this.centralAuthenticationService.grantProxyTicket(proxyGrantingTicket, targetService); return new ModelAndView(CONST_PROXY_SUCCESS, MODEL_SERVICE_TICKET, proxyTicket); } catch (final AbstractTicketException e) { return generateErrorView(e.getCode(), new Object[]{proxyGrantingTicket}, request); } catch (final UnauthorizedServiceException e) { return generateErrorView(CasProtocolConstants.ERROR_CODE_UNAUTHORIZED_SERVICE_PROXY, new Object[]{targetService}, request); } } /** * Gets the target service from the request. * * @param request the request * @return the target service */ private Service getTargetService(final HttpServletRequest request) { return this.webApplicationServiceFactory.createService(request); } /** * Generate error view stuffing the code and description * of the error into the model. View name is set to {@link #CONST_PROXY_FAILURE}. * * @param code the code * @param args the msg args * @return the model and view */ private ModelAndView generateErrorView(final String code, final Object[] args, final HttpServletRequest request) { final ModelAndView modelAndView = new ModelAndView(CONST_PROXY_FAILURE); modelAndView.addObject("code", StringEscapeUtils.escapeHtml4(code)); modelAndView.addObject("description", StringEscapeUtils.escapeHtml4(this.context.getMessage(code, args, code, request.getLocale()))); return modelAndView; } public void setApplicationContext(final ApplicationContext context) { this.context = context; } }