Hello,
i've been having a problem with one of my custom filters.
Goal:
Accepting or declining a session and Authentication based on maxLoginTime and/or maxInactiveTime using a CustomAuthenticationManager, but keeping the functionalities of the default AuthenticationManager. For instance sessionFixationStrategy.
Current situation:
I've got a customAuthenticationEntryPoint configured.
CustomAuthenticationManager.
SessionExpirationFilter(SessionManagementFilter)
Logging in works fine.
Problem:
When my filter clears the SecurityContext and sends a redirect I get the following error but only in my browser:
The page isn't redirecting properly
Firefox has detected that the server is redirecting the request for this address in a way that will never complete.
* This problem can sometimes be caused by disabling or refusing to accept cookies.
When I use my logout button I get the following error:
org.apache.jasper.JasperException: java.lang.IllegalStateException
The stacktrace points to the following line in my code:
nl.perslink.auth.SessionExpirationFilter.doFilter( SessionExpirationFilter.java:125)
This line is the filterChain.doFilter(request, response); line in the doFilter function of my sessionExpirationFilter.
This is my code of my custom sessionmanagementfilter(left out some not important code):
This is my security-configuration(I left out some useless configurations):Code:public class SessionExpirationFilter extends SessionManagementFilter implements ApplicationEventPublisherAware{ static final String FILTER_APPLIED = "__spring_security_session_expir_filter_applied"; private ApplicationEventPublisher eventPublisher; private final SecurityContextRepository securityContextRepository; private SessionAuthenticationStrategy sessionStrategy = new SessionFixationProtectionStrategy(); private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl(); private String invalidSessionUrl; private String sessionExpiredUrl; private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); public SessionExpirationFilter(SecurityContextRepository securityContextRepository) { super(securityContextRepository); this.securityContextRepository = securityContextRepository; } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws AuthenticationException ,IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (request.getAttribute(FILTER_APPLIED) != null) { filterChain.doFilter(request, response); return; } request.setAttribute(FILTER_APPLIED, Boolean.TRUE); if (!securityContextRepository.containsContext(request)) { if (authentication != null && !authenticationTrustResolver.isAnonymous(authentication)) { // The user has been authenticated during the current request, so call the session strategy try { sessionStrategy.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; } } else { // No security context or authentication present. Check for a session timeout if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) { logger.debug("Requested session ID" + request.getRequestedSessionId() + " is invalid."); if (invalidSessionUrl != null) { logger.debug("Redirecting to '" + invalidSessionUrl + "'"); redirectStrategy.sendRedirect(request, response, invalidSessionUrl); } } } } if(authentication!=null && request.getRequestedSessionId() != null && request.isRequestedSessionIdValid()) { setMaxInactiveTime(request, response, maxInactiveTime, maxSessionTime); } filterChain.doFilter(request, response); } private void setMaxInactiveTime(HttpServletRequest request, HttpServletResponse response, Integer maxInactiveTime, Integer maxLoginTime)throws AuthenticationException, IOException{ HttpSession session = request.getSession(false); if(session != null){ //do something to calc restSessionTime if(restSessionTime <=0){ SecurityContextHolder.createEmptyContext(); redirectStrategy.sendRedirect(request, response, sessionExpiredUrl); }else{ if(restSessionTime > maxInactiveTime){ session.setMaxInactiveInterval(maxInactiveTime*60); }else{ session.setMaxInactiveInterval(restSessionTime*60); } } } } public void setSessionAuthenticationStrategy(SessionAuthenticationStrategy sessionStrategy) { Assert.notNull(sessionStrategy, "authenticatedSessionStratedy must not be null"); this.sessionStrategy = sessionStrategy; } public void setInvalidSessionUrl(String invalidSessionUrl) { this.invalidSessionUrl = invalidSessionUrl; } public void setSessionExpiredUrl(String sessionExpiredUrl) { this.sessionExpiredUrl = sessionExpiredUrl; } public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) { Assert.notNull(failureHandler, "failureHandler cannot be null"); this.failureHandler = failureHandler; } public void setRedirectStrategy(RedirectStrategy redirectStrategy) { this.redirectStrategy = redirectStrategy; } }
Code:<security:http> <security:custom-filter ref="customizedFormLoginFilter" position="FORM_LOGIN_FILTER"/> <security:custom-filter ref="sessionExpirationFilter" after="FILTER_SECURITY_INTERCEPTOR" /> </security:http> <security:authentication-manager alias="authenticationManager"/> <!-- Custom login filter which replaces the default FORM_LOGIN_FILTER --> <bean id="customizedFormLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter" > <property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler"/> <property name="authenticationManager" ref="myAuthenticationManager"/> <!--Here it is the custom authenticationManager, login magic goes here --> <property name="allowSessionCreation" value="true" /> <!--Allow the application to create sessions--> <property name="authenticationDetailsSource" ref="webAuthenticationDetailsSource"/> </bean> <!-- Custom authentication manager --> <bean id="myAuthenticationManager" class="nl.perslink.auth.CustomAuthunticationManager"> <property name="userService" ref="userServiceImpl"/> </bean> <!-- Automatically receives AuthenticationEvent messages --> <bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener"/> <bean id="webAuthenticationDetailsSource" class="org.springframework.security.web.authentication.WebAuthenticationDetailsSource"/> <bean id="sessionExpirationFilter" class="nl.perslink.auth.SessionExpirationFilter"> <constructor-arg ref="httpSessionSecurityContextRepository"/> <property name="userService" ref="userServiceImpl"/> <property name="invalidSessionUrl" value="/login.jsp?error=2"/> <property name="sessionExpiredUrl" value="/login.jsp?error=3"/> </bean> <bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/> <!-- Authentication entry point, can be replaced easily if we are doing custom commence of invalid auths. --> <bean id="myAuthenticationEntryPoint" class="nl.perslink.auth.CustomAuthenticationEntryPoint" > <property name="loginFormUrl" value="/login.jsp"/> </bean> <!-- redirect url for failure of authentication --> <bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <constructor-arg value="/login.jsp?error=1"></constructor-arg> </bean>


