Skip to content

Instantly share code, notes, and snippets.

@banterCZ
Last active May 15, 2021 15:26
Show Gist options
  • Save banterCZ/5160269 to your computer and use it in GitHub Desktop.
Save banterCZ/5160269 to your computer and use it in GitHub Desktop.
InvalidSessionStrategy when session expired and ajax request is done.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Inspired by <a href="http://stackoverflow.com/questions/10143539/jsf-2-spring-security-3-x-and-richfaces-4-redirect-to-login-page-on-session-tim">StackOverflow.com</a>
* and by <a href="http://www.icesoft.org/wiki/display/ICE/Spring+Security#SpringSecurity-Step4%3AConfigureYourSpringSecurityredirectStrategy">Spring Security 3 and ICEfaces 3 Tutorial</a>.
*
* @author banterCZ
*/
public class JsfRedirectStrategy implements InvalidSessionStrategy {
private Logger logger = LoggerFactory.getLogger(getClass());
private static final String FACES_REQUEST_HEADER = "faces-request";
private String invalidSessionUrl;
/**
* {@inheritDoc}
*/
@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
boolean ajaxRedirect = "partial/ajax".equals(request.getHeader(FACES_REQUEST_HEADER));
if(ajaxRedirect) {
String contextPath = request.getContextPath();
String redirectUrl = contextPath + invalidSessionUrl;
logger.debug("Session expired due to ajax request, redirecting to '{}'", redirectUrl);
String ajaxRedirectXml = createAjaxRedirectXml(redirectUrl);
logger.debug("Ajax partial response to redirect: {}", ajaxRedirectXml);
response.setContentType("text/xml");
response.getWriter().write(ajaxRedirectXml);
} else {
String requestURI = getRequestUrl(request);
logger.debug("Session expired due to non-ajax request, starting a new session and redirect to requested url '{}'", requestURI);
request.getSession(true);
response.sendRedirect(requestURI);
}
}
private String getRequestUrl(HttpServletRequest request) {
StringBuffer requestURL = request.getRequestURL();
String queryString = request.getQueryString();
if (StringUtils.hasText(queryString)) {
requestURL.append("?").append(queryString);
}
return requestURL.toString();
}
private String createAjaxRedirectXml(String redirectUrl) {
return new StringBuilder()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.append("<partial-response><redirect url=\"")
.append(redirectUrl)
.append("\"></redirect></partial-response>")
.toString();
}
public void setInvalidSessionUrl(String invalidSessionUrl) {
this.invalidSessionUrl = invalidSessionUrl;
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<sec:http pattern="/pages/public/**" security="none"/>
<sec:http pattern="/javax.faces.resource/**" security="none"/>
<sec:http use-expressions="true" >
<sec:custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
<sec:intercept-url pattern="/pages/protected/**" access="isAuthenticated()" />
<sec:form-login login-page='/pages/public/login.xhtml' default-target-url="/pages/protected/index.xhtml"
authentication-failure-url="/pages/public/login.xhtml?failure=true" />
<sec:logout logout-success-url="/pages/public/login.xhtml"/>
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="joe" password="password" authorities="ROLE_USER"/>
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
<constructor-arg name="securityContextRepository" ref="httpSessionSecurityContextRepository" />
<property name="invalidSessionStrategy" ref="jsfRedirectStrategy" />
</bean>
<bean id="jsfRedirectStrategy" class="JsfRedirectStrategy">
<property name="invalidSessionUrl" value="/pages/public/error/viewExpired.xhtml" />
</bean>
<bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
</beans>
<ui:composition template="/WEB-INF/templates/public_layout.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<ui:param name="title" value="#{msg['error.viewExpired.title']}" />
<ui:define name="content">
#{msg['error.viewExpired.text']}
<h:outputLink value="#{header['referer']}">#{msg['link.back']}</h:outputLink>
</ui:define>
</ui:composition>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
@mhewedy
Copy link

mhewedy commented Nov 20, 2014

Great work, however, you shouldn't put the RedirectStrategy code inside your implementation of "InvalidSessionStrategy", however you should delegate the work to an implementation of RedirectStrategy instead. (exactly as SimpleRedirectInvalidSessionStrategy works.)

@AbdelhamidUPOND
Copy link

Great work, however, I added in the file of config
and in the face-config
< lifecycle>

web.util.CacheControlPhaseListener< /phase-listener>
< / lifecycle>

public class CacheControlPhaseListener implements PhaseListener {
private static final long serialVersionUID = 2475683599960651934L;
@OverRide
public void afterPhase(PhaseEvent event) {}

@Override
public void beforePhase(PhaseEvent event) {
    FacesContext facesContext = event.getFacesContext();
    HttpServletResponse response = (HttpServletResponse) facesContext
            .getExternalContext().getResponse();
    response.addHeader("Pragma", "no-cache");
    response.addHeader("Cache-Control", "no-cache");
    // Stronger according to blog comment below that references HTTP spec
    response.addHeader("Cache-Control", "no-store");
    response.addHeader("Cache-Control", "must-revalidate");
    // some date in the past
    response.addHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT");

}

@Override
public PhaseId getPhaseId() {
         return PhaseId.RENDER_RESPONSE;
}

}

otherwise many problems appear.
what do you think ?

@rogerio-ar-costa
Copy link

Worked like a charm, thank you!

@agustisanchez
Copy link

Thanks!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment