package org.apereo.cas.web.flow; import com.google.common.base.Throwables; import org.apereo.cas.CentralAuthenticationService; import org.apereo.cas.configuration.model.core.logout.LogoutProperties; import org.apereo.cas.logout.LogoutRequest; import org.apereo.cas.web.support.CookieRetrievingCookieGenerator; import org.apereo.cas.web.support.WebUtils; import org.pac4j.core.profile.ProfileManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.webflow.action.AbstractAction; import org.springframework.webflow.action.EventFactorySupport; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.RequestContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.List; /** * Terminates the CAS SSO session by destroying all SSO state data (i.e. TGT, cookies). * * @author Marvin S. Addison * @since 4.0.0 */ public class TerminateSessionAction extends AbstractAction { private static final Logger LOGGER = LoggerFactory.getLogger(TerminateSessionAction.class); private final EventFactorySupport eventFactorySupport = new EventFactorySupport(); private final CentralAuthenticationService centralAuthenticationService; private final CookieRetrievingCookieGenerator ticketGrantingTicketCookieGenerator; private final CookieRetrievingCookieGenerator warnCookieGenerator; private final LogoutProperties logoutProperties; public TerminateSessionAction(final CentralAuthenticationService centralAuthenticationService, final CookieRetrievingCookieGenerator tgtCookieGenerator, final CookieRetrievingCookieGenerator warnCookieGenerator, final LogoutProperties logoutProperties) { this.centralAuthenticationService = centralAuthenticationService; this.ticketGrantingTicketCookieGenerator = tgtCookieGenerator; this.warnCookieGenerator = warnCookieGenerator; this.logoutProperties = logoutProperties; } @Override public Event doExecute(final RequestContext requestContext) throws Exception { boolean terminateSession = true; if (logoutProperties.isConfirmLogout()) { terminateSession = isLogoutRequestConfirmed(requestContext); } if (terminateSession) { return terminate(requestContext); } return this.eventFactorySupport.event(this, CasWebflowConstants.STATE_ID_WARN); } /** * Terminates the CAS SSO session by destroying the TGT (if any) and removing cookies related to the SSO session. * * @param context Request context. * @return "success" */ public Event terminate(final RequestContext context) { // in login's webflow : we can get the value from context as it has already been stored try { final HttpServletRequest request = WebUtils.getHttpServletRequest(context); final HttpServletResponse response = WebUtils.getHttpServletResponse(context); String tgtId = WebUtils.getTicketGrantingTicketId(context); // for logout, we need to get the cookie's value if (tgtId == null) { tgtId = this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request); } if (tgtId != null) { LOGGER.debug("Destroying SSO session linked to ticket-granting ticket [{}]", tgtId); final List<LogoutRequest> logoutRequests = this.centralAuthenticationService.destroyTicketGrantingTicket(tgtId); WebUtils.putLogoutRequests(context, logoutRequests); } LOGGER.debug("Removing CAS cookies"); this.ticketGrantingTicketCookieGenerator.removeCookie(response); this.warnCookieGenerator.removeCookie(response); destroyApplicationSession(request, response); LOGGER.debug("Terminated all CAS sessions successfully."); return this.eventFactorySupport.success(this); } catch (final Exception e) { throw Throwables.propagate(e); } } /** * Destroy application session. * Also kills all delegated authn profiles via pac4j. * * @param request the request * @param response the response */ protected void destroyApplicationSession(final HttpServletRequest request, final HttpServletResponse response) { LOGGER.debug("Destroying application session"); final ProfileManager manager = WebUtils.getPac4jProfileManager(request, response); manager.logout(); final HttpSession session = request.getSession(); if (session != null) { session.invalidate(); } } private static boolean isLogoutRequestConfirmed(final RequestContext requestContext) { final HttpServletRequest request = WebUtils.getHttpServletRequest(requestContext); return request.getParameterMap().containsKey("LogoutRequestConfirmed"); } }