This is a note to myself mainly ( this is based on Oleg’s post btw, I just tried to simplified a little from here
To deal with ViewExpiredException with regular and ajax requests, do the following:
in faces-config.xml, have the following:
<factory>
<exception-handler-factory>
com.prime.DefaultExceptionHandlerFactory
</exception-handler-factory>
</factory>
<lifecycle>
<phase-listener>
com.prime.SecurityPhaseListener
</phase-listener>
</lifecycle>
in security.xml for Spring, we add a entry-point-ref as follows:
<http auto-config="false" access-denied-page="/accessDenied.xhtml" entry-point-ref="authenticationProcessingFilterEntryPoint">
where authenticationProcessingFilterEntryPoint is :
<beans:bean id="authenticationProcessingFilterEntryPoint" class="com.prime.AuthenticationProcessingFilterEntryPoint"> <beans:property name="loginFormUrl" value="/login.xhtml" /> <beans:property name="useForward" value="true" /> </beans:bean>
ok, now our java codes;
the SecurityPhaseListener is defined as:
package com.prime;
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.primefaces.context.DefaultRequestContext;
public class SecurityPhaseListener implements PhaseListener {
private static final long serialVersionUID = -101374487855763803L;
public void afterPhase(PhaseEvent event) {
}
public void beforePhase(PhaseEvent event) {
FacesContext fc = event.getFacesContext();
String loginPage = (String) fc.getExternalContext().getRequestMap().get(AuthenticationProcessingFilterEntryPoint.ATTRIBUTE_LOGIN_PAGE);
if (StringUtils.isNotBlank(loginPage)) {
doRedirect(fc, loginPage);
}
}
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
public void doRedirect(FacesContext fc, String redirectPage) throws FacesException {
ExternalContext ec = fc.getExternalContext();
try {
if (ec.isResponseCommitted()) {
return;
}
ec.redirect(ec.getRequestContextPath() + (redirectPage != null ? redirectPage : ""));
} catch (IOException e) {
throw new FacesException(e);
}
}
}
our AuthenticationProcessingFilterEntryPoint code is as follows:
package com.prime;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
/**
* Extended Spring AuthenticationProcessingFilterEntryPoint for playing together with JSF Ajax redirects.
*/
public class AuthenticationProcessingFilterEntryPoint extends LoginUrlAuthenticationEntryPoint
{
public static final String ATTRIBUTE_LOGIN_PAGE = "com.myproject.login.page";
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
if(request.getParameter("javax.faces.partial.ajax") != null )
request.setAttribute(ATTRIBUTE_LOGIN_PAGE, getLoginFormUrl());
super.commence(request, response, authException);
}
}
ok finally, the DefaultExceptionHandlerFactory classes which are as follows:
package com.prime;
import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.servlet.http.HttpSession;
public class DefaultExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public DefaultExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
@Override
public ExceptionHandler getWrapped() {
return this.wrapped;
}
@Override
public void handle() throws FacesException {
FacesContext facesContext = FacesContext.getCurrentInstance();
Iterator<ExceptionQueuedEvent> eventIterator = getUnhandledExceptionQueuedEvents().iterator();
ViewExpiredException viewExpiredException = getViewExpiredException(getUnhandledExceptionQueuedEvents());
if (viewExpiredException != null) {
String redirectUrl = invalidateSessionAndGetErrorPage(facesContext, viewExpiredException);
redirectToTheErrorPage(facesContext, redirectUrl);
} else if (eventIterator.hasNext()) {
String redirectUrl = "/error.html";
redirectToTheErrorPage(facesContext, redirectUrl);
}
}
private String invalidateSessionAndGetErrorPage(FacesContext facesContext, ViewExpiredException throwable) {
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}
return "/dashboard.xhtml";
}
private void redirectToTheErrorPage(FacesContext facesContext, String redirectUrl) {
SecurityPhaseListener spl = new SecurityPhaseListener();
spl.doRedirect(facesContext, redirectUrl);
}
private ViewExpiredException getViewExpiredException(Iterable<ExceptionQueuedEvent> unhandledExceptionQueuedEvents) {
for (ExceptionQueuedEvent event : unhandledExceptionQueuedEvents) {
ExceptionQueuedEventContext queuedEventContext = event.getContext();
if (queuedEventContext.getException() instanceof ViewExpiredException) {
return (ViewExpiredException) queuedEventContext.getException();
}
}
return null;
}
}
and our DefaultExceptionHandlerFactory is
package com.prime;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class DefaultExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public DefaultExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
@Override
public ExceptionHandler getExceptionHandler() {
ExceptionHandler eh = parent.getExceptionHandler();
eh = new DefaultExceptionHandler(eh);
return eh;
}
}
the codes in DefaultExceptionHandlerFactory can be changed to customize.
just a note myself.
Advertisement