In software programming, the use of frameworks makes things easy and saves a great deal of time for developers. In the Java world, Spring Security is one such framework that is worth consideration by developers. Spring Security is part of the larger Spring Projects Umbrella, and the framework can be used to implement security aspects in Java web applications. Spring Security makes a developer’s job easier and ensures that an application is secure by configuring the appropriate elements in the xml file. It also provides support classes and various filters, as well as support for custom requirements. It is worth nothing that Spring Security sometimes requires a bit more work to achieve specific, complex requirements, but the tool is, nevertheless, a worthwhile addition to any developer’s toolkit.One of the common requirements in web development is to gracefully exit from the application when a user session expires. In this article, we will look at how Spring Security can help a developer to easily configure and handle a session timeout, and explore the issues and workarounds that you’ll need to understand in order to successfully utilize the tool.
Configuration
The following explanation assumes that the reader understands the required configuration xml file needed to implement Spring Security, is the xml element where we need to make changes.
To tell Spring to show a separate page when the user session has expired, you can simply specify the URL value in the invalid-session-url attribute – and then, you are done! When the user tries to make a request after being idle for some time, and session has already timed out, Spring will direct the user to the specified page.
Problem
This configuration is very simple. But, it will create one problem. Even when a user logs out properly from the system, he or she will get the session expiration page instead of the login page (we’ll assume here that you have setup the login the URL as a logout-success-url in element).
This problem occurs because, when user logs out, Spring invalidates the user session. On the next request to show the login page, the browser will send the cached session ID to the server. But, since the session associated with the given ID is invalidated, Spring will redirect the user to the session expiration page as configured.
Workaround 1
One workaround to this problem is to tell Spring not to invalidate the session on logout event. This can be done by setting the value of invalidate-session attribute to “false” in element.
This configuration will keep the user session alive on the logout event, so the user will be redirected to the login page, rather than to the session expiration page. But you may not always be able to keep the session alive when the user logs out from the application. In that case, use Workaround 2.
Workaround 2
The other workaround is to delete the session cookie on the logout event. You can do so by using delete-cookies attribute of element. As you can see, we asked Spring to delete the cookie named “JSESSIONID” on the logout event. Because the browser will not send any session ID on the next request, Spring will direct the user to the login page, and thereby solve the problem.
This approach may work for some containers but not for others. For instance, if you are using Apache Tomcat version 7, this workaround will not succeed. In this case, Spring won’t remove the cookie in spite of the delete-cookies attribute value that is specified, because it can’t find the matched cookie path. When Tomcat sends the cookie to the browser, it appends the extra slash (“/”) to the end of the context path, e.g., path = “/foo/”. Tomcat has a good reason to do this because IE gets confused in sending cookies to the server for matching domains. For example, it will send the cookie meant for “/foo” to the domain “/foobar” as well. Please note that this behavior has been noted by other developers, but we have not personally verified this.
To solve this problem, Tomcat appends a slash at the end of the context path. Now, when you set the delete-cookie attribute, Spring tries to find the cookie for the path without a slash at the end. Because it doesn’t find it, the cookie will not be removed, resulting in the display of session expiration page instead of login page.
Luckily, Spring provides the flexibility to make custom changes in the default behavior. To solve the above problem, you need to write your own logout handler to remove the desired cookies. For that, we will need to use a “logout filter” instead of “” element (i.e. remove the entirely from the configuration file).
Sample Configuration
<beans:bean id=“logoutFilter” class=“org.springframework.security.web.authentication.logout.LogoutFilter”>
<beans:constructor-arg index=“0” value=“/login.html” />
<beans:constructor-arg index=“1”>
<beans:list>
<beans:beanid=“securityContextLogoutHandler” class=“org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler” />
<beans:bean id=“cookieClearingLogoutHandler” class=“com.xyz.CustomCookieClearingLogoutHandler” />
</beans:list>
</beans:constructor-arg>
<beans:property name=“filterProcessesUrl” value=“/j_spring_security_logout” />
</beans:bean>
Additionally, to ask Spring to use the logout filter, we need following entry in the <http> element.
<http>
<custom-filter position=”LOGOUT_FILTER” ref=”logoutFilter” />
</http>
As illustrated aboe, we have used Spring’s default LogoutFilter class with the first constructor argument specified for the logout success URL (which we kept the login page). This solution takes the second constructor argument as a list of LogoutHandlers. The first LogoutHandler class mentioned above is Spring’s default – the SecurityContextLogoutHandler class, which is responsible for invalidating the user session. The other LogoutHandler class is our custom implementation named CustomCoolieClearingLogoutHandler. This class will implement the LogoutHandler interface as shown in the following code snippet.
publicclass CustomCookieClearingLogoutHandler implements LogoutHandler {
@Override
publicvoid logout(HttpServletRequest request, HttpServletResponse response,
Authentication auth) {
Cookie cookieWithSlash = new Cookie(“JSESSIONID”, null);
//Tomcat adds extra slash at the end of context path (e.g. “/foo/”)
cookieWithSlash.setPath(request.getContextPath() + “/”);
cookieWithSlash.setMaxAge(0);
Cookie cookieWithoutSlash = new Cookie(“JSESSIONID”, null);
//JBoss doesn’t add extra slash at the end of context path (e.g. “/foo”)
cookieWithoutSlash.setPath(request.getContextPath());
cookieWithoutSlash.setMaxAge(0);
//Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
response.addCookie(cookieWithSlash); //For cookie added by Tomcat
response.addCookie(cookieWithoutSlash); //For cookie added by JBoss
}
}
As you can see, we programmatically removed the cookies with required path values for Tomcat and JBoss, and our custom LogoutHandler ensures that the session cookie is removed from the browser on the logout event, thereby displaying the login page instead of the session expiration page when a user logs out of the application using the logout button.
Summary
While Spring Security makes things easy to implement for most configurations, sometimes it requires bit of exploration and innovation to address complex or specific needs or environments. You can explore Spring’s other filter classes related to login, logout, authentication and other processes and use these to achieve dependable security for specific functions and to solve other configuration problems.