leodali leodali - 2 months ago 20
Java Question

SessionManagementFilter never calls SessionAuthenticationStrategy

I'm quite stuck migrating our web application from Wicket 1.4 to Wicket 6.20.
I'm also moving Spring Security to version 3.2.8.RELEASE from previous (and old) version 2.0.4.

Here it is a copy of Spring security context configuration:

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant" >
<security:filter-chain request-matcher-ref="requestMatcher"
filters="
securityContextPersistenceFilter,
concurrentSessionFilter,sessionManagementFilter"
pattern="/**" />
</security:filter-chain-map>
</bean>

<beans:bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<beans:constructor-arg ref="securityContextRepository"></beans:constructor-arg>
</beans:bean>

<beans:bean id="sessionManagementFilter"
class="org.springframework.security.web.session.SessionManagementFilter">
<beans:constructor-arg ref="securityContextRepository"></beans:constructor-arg>
<beans:constructor-arg ref="sas"></beans:constructor-arg>
</beans:bean>

<beans:bean id="requestMatcher" class="org.springframework.security.web.util.matcher.AntPathRequestMatcher" >
<beans:constructor-arg value="/**"></beans:constructor-arg>
</beans:bean>

<beans:bean id="concurrentSessionFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:constructor-arg ref="sessionRegistry" ></beans:constructor-arg>
<beans:constructor-arg value="/petrol/login" ></beans:constructor-arg>
</beans:bean>

<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="true" />
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>

<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />

<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="petrolAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>

<beans:bean name='securityContextRepository'
class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
<beans:property name='allowSessionCreation' value='true' />
</beans:bean>

<beans:bean id="petrolAuthenticationProvider"
class="it.loginet.petrol.infrastructure.security.PetrolAuthenticationProvider">
<beans:property name="utenteRepository" ref="utenteRepository" />
</beans:bean>


SessionManagementFilter should filter our Request, testing if concurrent logins are allowed for a user.
The problem is that when it comes to verify a successful Authentication, SecurityContextRepository already contains the SecurityContext, and it doesn't call "SessionAuthenticationStrategy.onAuthentication" method.

if (!securityContextRepository.containsContext(request)) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication != null && !trustResolver.isAnonymous(authentication)) {
// The user has been authenticated during the current request, so call the session strategy
try {
sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
} catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug("SessionAuthenticationStrategy rejected the authentication object", e);
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, e);

return;
}
.........


SaveToSessionResponseWrapper class save SPRING_SECURITY_KEY attribute on the HttpSession, the SessionManagementFilter already find this attribute on the HttpSession and actually skip the inner SessionAuthenticationStrategy validation.

What I'm doing wrong on the migration?

Answer

OK, I think I found solution to my problem..

SessionManagementFilter, as stated here (http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#ftn.d5e3442), doesn't recognize form logins authentication as I was using it in my application. Thus concurrency strategy inside this filter would be never called..

So I decided to extend ProviderManager class with a new SessionManagementProviderManager instance, overriding ProviderManager.authenticate() method to apply 1) initial authentication process using inner AuthenticationManager and 2)SessionAuthenticationStrategy.onAuthentication() on the resulting Authentication returned from point 1).

Maybe this answer can help someone else with same problems migrating Spring Security..

Comments