diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java index 14ec120..109aadd 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/configuration/ConfigurationKeys.java @@ -77,6 +77,5 @@ public interface ConfigurationKeys { ConfigurationKey ALLOWED_PROXY_CHAINS = new ConfigurationKey("allowedProxyChains", null); ConfigurationKey> TICKET_VALIDATOR_CLASS = new ConfigurationKey>("ticketValidatorClass", null); ConfigurationKey PROXY_CALLBACK_URL = new ConfigurationKey("proxyCallbackUrl", null); - ConfigurationKey FRONT_LOGOUT_PARAMETER_NAME = new ConfigurationKey("frontLogoutParameterName", "SAMLRequest"); ConfigurationKey RELAY_STATE_PARAMETER_NAME = new ConfigurationKey("relayStateParameterName", "RelayState"); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java index 5720a69..25d645c 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutFilter.java @@ -46,7 +46,6 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { if (!isIgnoreInitConfiguration()) { setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME)); setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME)); - setFrontLogoutParameterName(getString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME)); setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME)); setCasServerUrlPrefix(getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX)); HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST)); @@ -63,11 +62,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter { public void setLogoutParameterName(final String name) { HANDLER.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - HANDLER.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { HANDLER.setRelayStateParameterName(name); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java index de13582..26932db 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/session/SingleSignOutHandler.java @@ -57,12 +57,9 @@ public final class SingleSignOutHandler { /** The name of the artifact parameter. This is used to capture the session identifier. */ private String artifactParameterName = Protocol.CAS2.getArtifactParameterName(); - /** Parameter name that stores logout request for back channel SLO */ + /** Parameter name that stores logout request for SLO */ private String logoutParameterName = ConfigurationKeys.LOGOUT_PARAMETER_NAME.getDefaultValue(); - - /** Parameter name that stores logout request for front channel SLO */ - private String frontLogoutParameterName = ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(); - + /** Parameter name that stores the state of the CAS server webflow for the callback */ private String relayStateParameterName = ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(); @@ -75,7 +72,7 @@ public final class SingleSignOutHandler { private List safeParameters; - private LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy(); + private final LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy(); public void setSessionMappingStorage(final SessionMappingStorage storage) { this.sessionMappingStorage = storage; @@ -97,7 +94,7 @@ public final class SingleSignOutHandler { } /** - * @param name Name of parameter containing CAS logout request message for back channel SLO. + * @param name Name of parameter containing CAS logout request message for SLO. */ public void setLogoutParameterName(final String name) { this.logoutParameterName = name; @@ -109,14 +106,7 @@ public final class SingleSignOutHandler { public void setCasServerUrlPrefix(final String casServerUrlPrefix) { this.casServerUrlPrefix = casServerUrlPrefix; } - - /** - * @param name Name of parameter containing CAS logout request message for front channel SLO. - */ - public void setFrontLogoutParameterName(final String name) { - this.frontLogoutParameterName = name; - } - + /** * @param name Name of parameter containing the state of the CAS server webflow. */ @@ -135,7 +125,6 @@ public final class SingleSignOutHandler { if (this.safeParameters == null) { CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null."); CommonUtils.assertNotNull(this.logoutParameterName, "logoutParameterName cannot be null."); - CommonUtils.assertNotNull(this.frontLogoutParameterName, "frontLogoutParameterName cannot be null."); CommonUtils.assertNotNull(this.sessionMappingStorage, "sessionMappingStorage cannot be null."); CommonUtils.assertNotNull(this.relayStateParameterName, "relayStateParameterName cannot be null."); CommonUtils.assertNotNull(this.casServerUrlPrefix, "casServerUrlPrefix cannot be null."); @@ -165,32 +154,25 @@ public final class SingleSignOutHandler { } /** - * Determines whether the given request is a CAS back channel logout request. + * Determines whether the given request is a CAS logout request. * * @param request HTTP request. * * @return True if request is logout request, false otherwise. */ - private boolean isBackChannelLogoutRequest(final HttpServletRequest request) { - return "POST".equals(request.getMethod()) - && !isMultipartRequest(request) - && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, - this.safeParameters)); + private boolean isLogoutRequest(final HttpServletRequest request) { + if ("POST".equalsIgnoreCase(request.getMethod())) { + return !isMultipartRequest(request) + && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, + this.safeParameters)); + } + + if ("GET".equalsIgnoreCase(request.getMethod())) { + return CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters)); + } + return false; } - - /** - * Determines whether the given request is a CAS front channel logout request. Front Channel log out requests are only supported - * when the 'casServerUrlPrefix' value is set. - * - * @param request HTTP request. - * - * @return True if request is logout request, false otherwise. - */ - private boolean isFrontChannelLogoutRequest(final HttpServletRequest request) { - return "GET".equals(request.getMethod()) && CommonUtils.isNotBlank(this.casServerUrlPrefix) - && CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.frontLogoutParameterName)); - } - + /** * Process a request regarding the SLO process: record the session or destroy it. * @@ -203,26 +185,15 @@ public final class SingleSignOutHandler { logger.trace("Received a token request"); recordSession(request); return true; - - } else if (isBackChannelLogoutRequest(request)) { - logger.trace("Received a back channel logout request"); + } + + if (isLogoutRequest(request)) { + logger.trace("Received a logout request"); destroySession(request); return false; - - } else if (isFrontChannelLogoutRequest(request)) { - logger.trace("Received a front channel logout request"); - destroySession(request); - // redirection url to the CAS server - final String redirectionUrl = computeRedirectionToServer(request); - if (redirectionUrl != null) { - CommonUtils.sendRedirect(response, redirectionUrl); - } - return false; - - } else { - logger.trace("Ignoring URI for logout: {}", request.getRequestURI()); - return true; - } + } + logger.trace("Ignoring URI for logout: {}", request.getRequestURI()); + return true; } /** @@ -245,7 +216,7 @@ public final class SingleSignOutHandler { try { this.sessionMappingStorage.removeBySessionById(session.getId()); } catch (final Exception e) { - // ignore if the session is already marked as invalid. Nothing we can do! + // ignore if the session is already marked as invalid. Nothing we can do! } sessionMappingStorage.addSessionById(token, session); } @@ -286,16 +257,17 @@ public final class SingleSignOutHandler { * @param request HTTP request containing a CAS logout message. */ private void destroySession(final HttpServletRequest request) { - final String logoutMessage; - // front channel logout -> the message needs to be base64 decoded + decompressed - if (isFrontChannelLogoutRequest(request)) { - logoutMessage = uncompressLogoutMessage(CommonUtils.safeGetParameter(request, - this.frontLogoutParameterName)); - } else { - logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters); + String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters); + if (CommonUtils.isBlank(logoutMessage)) { + logger.error("Could not locate logout message of the request from {}", this.logoutParameterName); + return; } + + if (!logoutMessage.contains("SessionIndex")) { + logoutMessage = uncompressLogoutMessage(logoutMessage); + } + logger.trace("Logout request:\n{}", logoutMessage); - final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex"); if (CommonUtils.isNotBlank(token)) { final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token); @@ -314,33 +286,6 @@ public final class SingleSignOutHandler { } } - /** - * Compute the redirection url to the CAS server when it's a front channel SLO - * (depending on the relay state parameter). - * - * @param request The HTTP request. - * @return the redirection url to the CAS server. - */ - private String computeRedirectionToServer(final HttpServletRequest request) { - final String relayStateValue = CommonUtils.safeGetParameter(request, this.relayStateParameterName); - // if we have a state value -> redirect to the CAS server to continue the logout process - if (CommonUtils.isNotBlank(relayStateValue)) { - final StringBuilder buffer = new StringBuilder(); - buffer.append(casServerUrlPrefix); - if (!this.casServerUrlPrefix.endsWith("/")) { - buffer.append("/"); - } - buffer.append("logout?_eventId=next&"); - buffer.append(this.relayStateParameterName); - buffer.append("="); - buffer.append(CommonUtils.urlEncode(relayStateValue)); - final String redirectUrl = buffer.toString(); - logger.debug("Redirection url to the CAS server: {}", redirectUrl); - return redirectUrl; - } - return null; - } - private boolean isMultipartRequest(final HttpServletRequest request) { return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart"); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java index 5fe1337..22cb830 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/Cas20ProxyReceivingTicketValidationFilter.java @@ -54,7 +54,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal TOLERANCE.getName(), IGNORE_PATTERN.getName(), IGNORE_URL_PATTERN_TYPE.getName(), HOSTNAME_VERIFIER.getName(), HOSTNAME_VERIFIER_CONFIG.getName(), EXCEPTION_ON_VALIDATION_FAILURE.getName(), REDIRECT_AFTER_VALIDATION.getName(), USE_SESSION.getName(), SECRET_KEY.getName(), CIPHER_ALGORITHM.getName(), PROXY_RECEPTOR_URL.getName(), PROXY_GRANTING_TICKET_STORAGE_CLASS.getName(), MILLIS_BETWEEN_CLEAN_UPS.getName(), ACCEPT_ANY_PROXY.getName(), ALLOWED_PROXY_CHAINS.getName(), TICKET_VALIDATOR_CLASS.getName(), - PROXY_CALLBACK_URL.getName(), FRONT_LOGOUT_PARAMETER_NAME.getName(), RELAY_STATE_PARAMETER_NAME.getName() + PROXY_CALLBACK_URL.getName(), RELAY_STATE_PARAMETER_NAME.getName() }; /** diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java index 93fd665..1a4f4e4 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutFilterTests.java @@ -84,32 +84,32 @@ public class SingleSignOutFilterTests { assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); } - @Test - public void frontChannelRequest() throws IOException, ServletException { - final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); - request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage); - request.setMethod("GET"); - final MockHttpSession session = new MockHttpSession(); - SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session); - filter.doFilter(request, response, filterChain); - assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); - assertNull(response.getRedirectedUrl()); - } +// @Test +// public void frontChannelRequest() throws IOException, ServletException { +// final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); +// request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); +// request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage); +// request.setMethod("GET"); +// final MockHttpSession session = new MockHttpSession(); +// SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session); +// filter.doFilter(request, response, filterChain); +// assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); +// assertNull(response.getRedirectedUrl()); +// } - @Test - public void frontChannelRequestRelayState() throws IOException, ServletException { - final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); - request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); - request.setParameter(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(), RELAY_STATE); - request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage + "&" + - ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE); - request.setMethod("GET"); - final MockHttpSession session = new MockHttpSession(); - SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session); - filter.doFilter(request, response, filterChain); - assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); - assertEquals(CAS_SERVER_URL_PREFIX + "/logout?_eventId=next&" + - ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl()); - } +// @Test +// public void frontChannelRequestRelayState() throws IOException, ServletException { +// final String logoutMessage = LogoutMessageGenerator.generateFrontChannelLogoutMessage(TICKET); +// request.setParameter(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue(), logoutMessage); +// request.setParameter(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue(), RELAY_STATE); +// request.setQueryString(ConfigurationKeys.FRONT_LOGOUT_PARAMETER_NAME.getDefaultValue() + "=" + logoutMessage + "&" + +// ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE); +// request.setMethod("GET"); +// final MockHttpSession session = new MockHttpSession(); +// SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().addSessionById(TICKET, session); +// filter.doFilter(request, response, filterChain); +// assertNull(SingleSignOutFilter.getSingleSignOutHandler().getSessionMappingStorage().removeSessionByMappingId(TICKET)); +// assertEquals(CAS_SERVER_URL_PREFIX + "/logout?_eventId=next&" + +// ConfigurationKeys.RELAY_STATE_PARAMETER_NAME.getDefaultValue() + "=" + RELAY_STATE, response.getRedirectedUrl()); +// } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java index 365a25e..661cb61 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/session/SingleSignOutHandlerTests.java @@ -52,7 +52,6 @@ public final class SingleSignOutHandlerTests { public void setUp() throws Exception { handler = new SingleSignOutHandler(); handler.setLogoutParameterName(LOGOUT_PARAMETER_NAME); - handler.setFrontLogoutParameterName(FRONT_LOGOUT_PARAMETER_NAME); handler.setRelayStateParameterName(RELAY_STATE_PARAMETER_NAME); handler.setArtifactParameterName(ARTIFACT_PARAMETER_NAME); handler.setCasServerUrlPrefix(URL); diff --git a/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java b/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java index 9941651..00c63dc 100644 --- a/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java +++ b/cas-client-integration-tomcat-v6/src/main/java/org/jasig/cas/client/tomcat/v6/SingleSignOutValve.java @@ -51,11 +51,7 @@ public class SingleSignOutValve extends AbstractLifecycleValve implements Sessio public void setLogoutParameterName(final String name) { this.handler.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - this.handler.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { this.handler.setRelayStateParameterName(name); } diff --git a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java index 62ac214..e7cd85d 100644 --- a/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java +++ b/cas-client-integration-tomcat-v7/src/main/java/org/jasig/cas/client/tomcat/v7/SingleSignOutValve.java @@ -55,11 +55,7 @@ public class SingleSignOutValve extends ValveBase implements SessionListener { public void setLogoutParameterName(final String name) { this.handler.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - this.handler.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { this.handler.setRelayStateParameterName(name); } diff --git a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java index 02fe955..de77527 100644 --- a/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java +++ b/cas-client-integration-tomcat-v8/src/main/java/org/jasig/cas/client/tomcat/v8/SingleSignOutValve.java @@ -55,11 +55,7 @@ public class SingleSignOutValve extends ValveBase implements SessionListener { public void setLogoutParameterName(final String name) { this.handler.setLogoutParameterName(name); } - - public void setFrontLogoutParameterName(final String name) { - this.handler.setFrontLogoutParameterName(name); - } - + public void setRelayStateParameterName(final String name) { this.handler.setRelayStateParameterName(name); }