I have an object that's marked as @ConversationScoped and is used between many steps of a wizard.
This works perfectly except that when my user's are login in, the SessionFixationProtectionStrategy of Spring calls the session.invalidate() method to recreate a new session with a new id. It then goes and reattach the attributes of the invalidated session to the new one.
The problem is that there's a WeldListener instance that is bound to the sessionDestroyed event and that will kill @ConversationScoped instances that are bound to the HttpSession object.
I have disabled the SessionFixationProtectionStrategy and am now using NullAuthenticatedSessionStrategy which does nothing, but I would still like to keep the Session Fixation strategy to protect my site from this.
Any suggestions on how to work around this?
Here's a strategy I'm using:
You need to copy the SessionFixationProtectionStrategy class to be able to implement this since there are no appropriate hooks already in place. Here's the onAuthenticate.
public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
boolean hadSessionAlready = request.getSession(false) != null;
if (!hadSessionAlready && !alwaysCreateSession) {
// Session fixation isn't a problem if there's no session
return;
}
// Create new session if necessary
HttpSession session = request.getSession();
if (hadSessionAlready && request.isRequestedSessionIdValid()) {
// We need to migrate to a new session
String originalSessionId = session.getId();
if (logger.isDebugEnabled()) {
logger.debug("Invalidating session with Id '" + originalSessionId +"' " + (migrateSessionAttributes ?
"and" : "without") + " migrating attributes.");
}
String id = weldAwareSessionFixationProtectionStrategyHelper.beforeInvalidateSession( request );
Map<String, Object> attributesToMigrate = extractAttributes(session);
for( String key : attributesToMigrate.keySet() ) {
session.removeAttribute( key );
}
session.invalidate();
session = request.getSession(true); // we now have a new session
if (logger.isDebugEnabled()) {
logger.debug("Started new session: " + session.getId());
}
if (originalSessionId.equals(session.getId())) {
logger.warn("Your servlet container did not change the session ID when a new session was created. You will" +
" not be adequately protected against session-fixation attacks");
}
transferAttributes(attributesToMigrate, session);
weldAwareSessionFixationProtectionStrategyHelper.afterCreateNewSession( request, id );
onSessionChange(originalSessionId, session, authentication);
}
}
... and here's the WeldAwareSessionFixationProtectionStrategyHelper
@ApplicationScoped
public class WeldAwareSessionFixationProtectionStrategyHelper {
@Inject
private HttpSessionContext httpSessionContext;
@Inject
private HttpConversationContext httpConversationContext;
public String beforeInvalidateSession( HttpServletRequest httpServletRequest ) {
String currentId = null;
if( !httpConversationContext.getCurrentConversation().isTransient() ) {
currentId = httpConversationContext.getCurrentConversation().getId();
}
httpConversationContext.deactivate();
httpConversationContext.dissociate( httpServletRequest );
httpSessionContext.deactivate();
httpSessionContext.dissociate( httpServletRequest );
return currentId;
}
public void afterCreateNewSession( HttpServletRequest httpServletRequest, String cid ) {
httpSessionContext.associate( httpServletRequest );
httpSessionContext.activate();
httpConversationContext.associate( httpServletRequest );
if( cid == null ) {
httpConversationContext.activate();
} else {
httpConversationContext.activate( cid );
}
}
}