With Spring security session creation and destruction is managed by the framework. Along with the session management code, we often tend to have some other activities performed. For e.g. I would like a count of the sessions created. As the code is now within Spring how do we add our audit code ? In a simple application the solution would be to add a HttpSessionListener.
Accordingly in my web.xml:
Spring Security provides a workaround for the problem. They have implemented a listener - HttpSessionEventPublisher.
Accordingly in my web.xml:
<listener>The code for the listener would be :
<listener-class>com.web.SessionCounter</listener-class>
</listener>
publicclass SessionCounter implements HttpSessionListener {Now whenever Spring creates a session, my listener is activated and the message will be logged to the console.
privateint counter = 0;
@Override
publicvoid sessionCreated(HttpSessionEvent event) {
counter++;
System.out.println("Total sessions created " + counter);
}
// other methods
}
Total sessions created 1The limitation with this approach is that the above listener is outside the Spring environment. If we need to access beans here, then the code gets complicated.
Spring Security provides a workaround for the problem. They have implemented a listener - HttpSessionEventPublisher.
publicclassHttpSessionEventPublisher implements HttpSessionListener {As seen the Listener is similar to my listener in that both receive the HttpSessionEvent when a session is created anywhere within the application. The HttpSessionEventPublisher class however converts this event to a Spring event.It publishes the event to the ApplicationContext. Any bean that listens for this event will now be made aware of Session creation. The 2 steps to do the above would be:
// ... code
@Override
publicvoid sessionCreated(HttpSessionEvent event) {
HttpSessionCreatedEvent e = new HttpSessionCreatedEvent(
event.getSession());
Log log = LogFactory.getLog(LOGGER_NAME);
if (log.isDebugEnabled()) {
log.debug("Publishing event: " + e);
}
getContext(event.getSession().getServletContext()).publishEvent(e);
}
// other methods
}
- Update the deployment descriptor:
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener> - Create the bean for the task:
<beans:bean class="com.web.SessionCreatedListener"/>
publicclassSessionCreatedListener implementsIf we run the code, the logs are as below:
ApplicationListener<HttpSessionCreatedEvent> {
// as this is a bean, the listener code executes within the Spring
// Security Framework
privateint counter = 0;
@Override
publicvoid onApplicationEvent(
HttpSessionCreatedEvent httpSessionCreatedEvent) {
counter++;
System.out.println("Total sessions created " + counter);
Date timestamp = new Date(httpSessionCreatedEvent.getTimestamp());
System.out.println("Session created at "
+ new SimpleDateFormat("yyyy-MM-dd").format(timestamp)
+ " and session is " + httpSessionCreatedEvent.getSession());
}
}
DEBUG HttpSessionEventPublisher:66 - Publishing event:Similarly for Session destroy, the beans need to listen for the HttpSessionDestroyedEvent. This one is also from the HttpSessionEventPublisher class (sessionDestroyed method). The HttpSessionEventPublisher also plays an important role in setting limits on the maximum number of concurrent sessions for a user.
org.springframework.security.web.session.HttpSessionCreatedEvent
[source=org.apache.catalina.session.StandardSessionFacade@195f463]
TRACE XmlWebApplicationContext:332 - Publishing event in Root
WebApplicationContext: org.springframework.security.web.session.HttpSessionCreatedEvent
[source=org.apache.catalina.session.StandardSessionFacade@195f463]
Total sessions created 2
Session created at 2013-08-12 and session is
org.apache.catalina.session.StandardSessionFacade@195f463