I am developing a webapp that uses Spring Security as security layer.
One important feature for us is to know which user is accessing the application, and how many time they are spending on it.
I'm not sure how to deal with it. Is there some other framework that deals with this kind of usage statistics?
Is there some way to use Spring Security itself to deal with it?
// I'm reading more about Spring Security and it seems that its filters can help me. Any progress will be shared here.
I think one of the solutions I can think of is using a HttpSessionListener, If you implement a Session listener you could capture the time as and when a new user session is created and destroyed, You could leverage your spring security context holder to get a hold of the uniquename/userid of the logged in user
I am thinking some thing like this
public class SesssionListenerImpl implements HttpSessionListener
{
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent)
{
String uniqueName = SecurityContextHolder.getContext().getAuthentication().getName();
String sessionId = httpSessionEvent.getSession().getId();
long beginTimeInSeconds = System.currentTimeMillis()/1000;
//create a record and persist to data base with sessionId, uniquename, sessionBeginTime
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent)
{
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
httpSessionEvent.getSession().getId();
long endTime = System.currentTimeMillis()/1000;
//load the record based on sessionId
//update the record with sessionEndTime
}
}
That being said there are few down sides to this approach, If the HTTP Session never gets invalidated then you will end up with some sessions with no end time.
UPDATE
You are right I think you could use spring application event mechanism, to do that add this to your web.xml, This listener publishes HTTP session events other wise you won't be able to access session events even if you implement ApplicationListener
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
Now add a new class that implements ApplicationListener
@Service
public class ApplicationSecurityListener implements ApplicationListener<ApplicationEvent>
{
@Override
public void onApplicationEvent(ApplicationEvent event)
{
if ( event instanceof AuthorizationFailureEvent )
{
AuthorizationFailureEvent authorizationFailureEvent = ( AuthorizationFailureEvent ) event;
System.out.println ( "not authorized:" + authorizationFailureEvent );
}
else if ( event instanceof AuthenticationFailureBadCredentialsEvent )
{
AuthenticationFailureBadCredentialsEvent badCredentialsEvent = ( AuthenticationFailureBadCredentialsEvent ) event;
System.out.println ( "badCredentials:" + badCredentialsEvent );
}
//login success event
else if ( event instanceof AuthenticationSuccessEvent )
{
AuthenticationSuccessEvent authenticationSuccessEvent = ( AuthenticationSuccessEvent ) event;
//this will provide user id and password but no session, get source has all the user information in security context
System.out.println ( "AuthenticationSuccessEvent:" + authenticationSuccessEvent.getSource() );
}
//this event will published if you add the HttpSessionEventPublisher to web.xml
else if ( event instanceof SessionDestroyedEvent )
{
SessionDestroyedEvent sessinEvent = ( SessionDestroyedEvent ) event;
System.out.println ( "SessionDestroyedEvent:" + sessinEvent.getId() );
//load session if it is not empty
if(sessinEvent.getSecurityContext() != null)
{
System.out.println ( "SessionDestroyedEvent:" + sessinEvent.getSecurityContext().getAuthentication().getName() );
//update the session with endTime
}
}
else
{
//System.out.println ( "undefined: " + event.getClass ().getName () );
}
}
}
There is another event if you would like to capture logout by itself, You can implement LogoutHandler that gives you access to logut event.