Skip to content

Commit

Permalink
refactor LogoutHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
leleuj committed Jul 27, 2016
1 parent aff50dd commit 07aca33
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 87 deletions.
5 changes: 3 additions & 2 deletions pac4j-cas/src/main/java/org/pac4j/cas/client/CasClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.pac4j.cas.config.CasProtocol;
import org.pac4j.cas.credentials.authenticator.CasAuthenticator;
import org.pac4j.cas.credentials.extractor.TicketAndLogoutRequestExtractor;
import org.pac4j.cas.logout.CasLogoutHandler;
import org.pac4j.cas.logout.CasSingleSignOutHandler;
import org.pac4j.cas.logout.LogoutHandler;
import org.pac4j.cas.profile.CasProfile;
Expand Down Expand Up @@ -158,12 +159,12 @@ public void setGateway(final boolean gateway) {
}

@Deprecated
public LogoutHandler getLogoutHandler() {
public CasLogoutHandler getLogoutHandler() {
return configuration.getLogoutHandler();
}

@Deprecated
public void setLogoutHandler(final LogoutHandler logoutHandler) {
public void setLogoutHandler(final CasLogoutHandler logoutHandler) {
configuration.setLogoutHandler(logoutHandler);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import org.jasig.cas.client.validation.*;
import org.pac4j.cas.client.CasProxyReceptor;
import org.pac4j.cas.logout.CasLogoutHandler;
import org.pac4j.cas.logout.CasSingleSignOutHandler;
import org.pac4j.cas.logout.LogoutHandler;
import org.pac4j.cas.logout.NoLogoutHandler;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.J2EContext;
Expand All @@ -25,6 +25,10 @@ public class CasConfiguration extends InitializableWebObject {

public static final String SERVICE_PARAMETER = "service";

public final static String LOGOUT_REQUEST_PARAMETER = "logoutRequest";

public final static String SESSION_INDEX_TAG = "SessionIndex";

private String encoding = HttpConstants.UTF8_ENCODING;

private String loginUrl;
Expand All @@ -43,7 +47,7 @@ public class CasConfiguration extends InitializableWebObject {

private ProxyList allowedProxyChains = new ProxyList();

private LogoutHandler logoutHandler;
private CasLogoutHandler logoutHandler;

private TicketValidator ticketValidator;

Expand Down Expand Up @@ -250,11 +254,11 @@ public void setAllowedProxyChains(final ProxyList allowedProxyChains) {
this.allowedProxyChains = allowedProxyChains;
}

public LogoutHandler getLogoutHandler() {
public CasLogoutHandler getLogoutHandler() {
return logoutHandler;
}

public void setLogoutHandler(final LogoutHandler logoutHandler) {
public void setLogoutHandler(final CasLogoutHandler logoutHandler) {
this.logoutHandler = logoutHandler;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package org.pac4j.cas.credentials.extractor;

import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.context.ContextHelper;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.TokenCredentials;
import org.pac4j.core.credentials.extractor.TokenCredentialsExtractor;
Expand Down Expand Up @@ -40,16 +44,22 @@ protected void internalInit(final WebContext context) {
@Override
public TokenCredentials extract(WebContext context) throws HttpAction {
// like the SingleSignOutFilter from the Apereo CAS client:
if (configuration.getLogoutHandler().isTokenRequest(context)) {
if (isTokenRequest(context)) {
final String ticket = context.getRequestParameter(CasConfiguration.TICKET_PARAMETER);
configuration.getLogoutHandler().recordSession(context, ticket);
final TokenCredentials casCredentials = new TokenCredentials(ticket, clientName);
logger.debug("casCredentials: {}", casCredentials);
return casCredentials;
}

if (configuration.getLogoutHandler().isLogoutRequest(context)) {
configuration.getLogoutHandler().destroySession(context);
if (isLogoutRequest(context)) {
final String logoutMessage = context.getRequestParameter(CasConfiguration.LOGOUT_REQUEST_PARAMETER);
logger.trace("Logout request:\n{}", logoutMessage);

final String sessionId = XmlUtils.getTextForElement(logoutMessage, CasConfiguration.SESSION_INDEX_TAG);
if (CommonUtils.isNotBlank(sessionId)) {
configuration.getLogoutHandler().destroySession(context, sessionId);
}
final String message = "logout request: no credential returned";
logger.debug(message);
throw HttpAction.ok(message, context);
Expand All @@ -58,6 +68,22 @@ public TokenCredentials extract(WebContext context) throws HttpAction {
return null;
}

protected boolean isTokenRequest(final WebContext context) {
return ContextHelper.isGet(context) &&
isMultipartRequest(context) &&
context.getRequestParameter(CasConfiguration.TICKET_PARAMETER) != null;
}

private boolean isMultipartRequest(final WebContext context) {
final String contentType = context.getRequestHeader(HttpConstants.CONTENT_TYPE_HEADER);
return contentType != null && contentType.toLowerCase().startsWith("multipart");
}

protected boolean isLogoutRequest(final WebContext context) {
return ContextHelper.isPost(context)
&& context.getRequestParameter(CasConfiguration.LOGOUT_REQUEST_PARAMETER) != null;
}

public CasConfiguration getConfiguration() {
return configuration;
}
Expand Down
38 changes: 38 additions & 0 deletions pac4j-cas/src/main/java/org/pac4j/cas/logout/CasLogoutHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.pac4j.cas.logout;

import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.context.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This interface defines how to handle CAS logout request on client side.
*
* @author Jerome Leleu
* @since 1.9.2
*/
public abstract class CasLogoutHandler<C extends WebContext> implements LogoutHandler<C> {

protected final Logger logger = LoggerFactory.getLogger(getClass());

@Override
public void destroySession(C context) {
final String logoutMessage = context.getRequestParameter(CasConfiguration.LOGOUT_REQUEST_PARAMETER);
logger.trace("Logout request:\n{}", logoutMessage);

final String sessionId = XmlUtils.getTextForElement(logoutMessage, CasConfiguration.SESSION_INDEX_TAG);
if (CommonUtils.isNotBlank(sessionId)) {
destroySession(context, sessionId);
}
}

/**
* Destroys the current web session for the given session identifier.
*
* @param context the web context
* @param sessionId the session identifier
*/
public abstract void destroySession(C context, String sessionId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@
import org.jasig.cas.client.session.SessionMappingStorage;
import org.jasig.cas.client.session.SingleSignOutHandler;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.XmlUtils;
import org.pac4j.cas.client.CasClient;
import org.pac4j.core.context.J2EContext;
import org.pac4j.core.context.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -27,7 +25,7 @@
* @author Jerome Leleu
* @since 1.4.0
*/
public class CasSingleSignOutHandler implements LogoutHandler {
public class CasSingleSignOutHandler extends CasLogoutHandler<J2EContext> {

protected static final Logger logger = LoggerFactory.getLogger(CasSingleSignOutHandler.class);

Expand All @@ -43,33 +41,11 @@ public class CasSingleSignOutHandler implements LogoutHandler {

private LogoutStrategy logoutStrategy = isServlet30() ? new Servlet30LogoutStrategy() : new Servlet25LogoutStrategy();

/**
* Construct an instance.
*/
public CasSingleSignOutHandler() {
}
public CasSingleSignOutHandler() { }

@Override
public boolean isTokenRequest(final WebContext context) {
final J2EContext j2eContext = (J2EContext) context;
return CommonUtils.isNotBlank(CommonUtils.safeGetParameter(j2eContext.getRequest(), this.artifactParameterName,
this.safeParameters));
}

@Override
public boolean isLogoutRequest(final WebContext context) {
final J2EContext j2eContext = (J2EContext) context;
HttpServletRequest request = j2eContext.getRequest();
return "POST".equals(request.getMethod())
&& !isMultipartRequest(request)
&& CommonUtils.isNotBlank(CommonUtils.safeGetParameter(request, this.logoutParameterName,
this.safeParameters));
}

@Override
public void recordSession(final WebContext context, final String ticket) {
final J2EContext j2eContext = (J2EContext) context;
HttpServletRequest request = j2eContext.getRequest();
public void recordSession(final J2EContext context, final String ticket) {
final HttpServletRequest request = context.getRequest();
final HttpSession session = request.getSession(this.eagerlyCreateSessions);

if (session == null) {
Expand All @@ -91,35 +67,23 @@ public void recordSession(final WebContext context, final String ticket) {
}

@Override
public void destroySession(final WebContext context) {
final J2EContext j2eContext = (J2EContext) context;
HttpServletRequest request = j2eContext.getRequest();
final String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters);
logger.trace("Logout request:\n{}", logoutMessage);

final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex");
if (CommonUtils.isNotBlank(token)) {
final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token);

if (session != null) {
String sessionID = session.getId();

logger.debug("Invalidating session [{}] for token [{}]", sessionID, token);

try {
session.invalidate();
} catch (final IllegalStateException e) {
logger.debug("Error invalidating session.", e);
}
this.logoutStrategy.logout(request);
public void destroySession(final J2EContext context, final String sessionId) {
final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(sessionId);
final HttpServletRequest request = context.getRequest();
if (session != null) {
String sessionID = session.getId();

logger.debug("Invalidating session [{}] for token [{}]", sessionID, sessionId);

try {
session.invalidate();
} catch (final IllegalStateException e) {
logger.debug("Error invalidating session.", e);
}
this.logoutStrategy.logout(request);
}
}

private boolean isMultipartRequest(final HttpServletRequest request) {
return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart");
}

private static boolean isServlet30() {
try {
return HttpServletRequest.class.getMethod("logout") != null;
Expand Down
14 changes: 8 additions & 6 deletions pac4j-cas/src/main/java/org/pac4j/cas/logout/LogoutHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,43 @@
import org.pac4j.core.context.WebContext;

/**
* This interface defines how to handle CAS logout request on client side.
* Replaced by the {@link CasLogoutHandler}.
*
* @author Jerome Leleu
* @since 1.4.0
* @deprecated
*/
public interface LogoutHandler {
@Deprecated
public interface LogoutHandler<C extends WebContext> {

/**
* Defines if this request is a token one.
*
* @param context the web context
* @return if this request is a token one
*/
boolean isTokenRequest(WebContext context);
default boolean isTokenRequest(C context) { return false; }

/**
* Defines if this request is a logout one.
*
* @param context the web context
* @return if this request is a logout one
*/
boolean isLogoutRequest(WebContext context);
default boolean isLogoutRequest(C context) { return false; }

/**
* Associates a token request with the current web session.
*
* @param context the web context
* @param ticket the service ticket
*/
void recordSession(WebContext context, String ticket);
void recordSession(C context, String ticket);

/**
* Destroys the current web session for the given CAS logout request.
*
* @param context the web context
*/
void destroySession(WebContext context);
void destroySession(C context);
}
24 changes: 5 additions & 19 deletions pac4j-cas/src/main/java/org/pac4j/cas/logout/NoLogoutHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.pac4j.cas.logout;

import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.context.WebContext;

/**
Expand All @@ -9,26 +8,13 @@
* @author Jerome Leleu
* @since 1.4.0
*/
public class NoLogoutHandler implements LogoutHandler {

private static final String LOGOUT_REQUEST_PARAMETER = "logoutRequest";

@Override
public boolean isTokenRequest(final WebContext context) {
return context.getRequestParameter(CasConfiguration.TICKET_PARAMETER) != null;
}

@Override
public boolean isLogoutRequest(final WebContext context) {
return "POST".equals(context.getRequestMethod())
&& context.getRequestParameter(LOGOUT_REQUEST_PARAMETER) != null;
}

public class NoLogoutHandler<C extends WebContext> extends CasLogoutHandler<C> {

@Override
public void recordSession(final WebContext context, final String ticket) {
public void recordSession(final C context, final String ticket) {
}

@Override
public void destroySession(final WebContext context) {
public void destroySession(final C context, final String sessionId) {
}
}
10 changes: 10 additions & 0 deletions pac4j-core/src/main/java/org/pac4j/core/context/ContextHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ public static Cookie getCookie(final WebContext context, final String name) {
return getCookie(context.getRequestCookies(), name);
}

/**
* Whether it is a GET request.
*
* @param context the web context
* @return whether it is a GET request
*/
public static boolean isGet(final WebContext context) {
return HttpConstants.HTTP_METHOD.GET.name().equalsIgnoreCase(context.getRequestMethod());
}

/**
* Whether it is a POST request.
*
Expand Down

0 comments on commit 07aca33

Please sign in to comment.