14

I have a custom logout filter called six times. Twice as soon I try to access the application, twice when I enter username/password and click on 'Login' and then twice again when I click on 'logout'.

What am I doing wrong?

Configuration:

<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN_FUNCTIONS')" />      
    <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />

    <form-login login-page="/login"
        authentication-success-handler-ref="customAuthenticationSuccessHandlerBean"
        authentication-failure-handler-ref="customAuthenticationFailureHandlerBean" />
    <logout invalidate-session="true" success-handler-ref="logoutHandlerBean" />
    <session-management session-fixation-protection="migrateSession">
        <concurrency-control max-sessions="1"
            expired-url="/login_sessionexpired" />
    </session-management>

    <custom-filter before="LOGOUT_FILTER" ref="customLogoutFilter" />
</http>

<beans:bean id="customLogoutFilter" class="com.hurontg.libms.security.CustomLogoutFilter" />

The filter:

public class CustomLogoutFilter extends OncePerRequestFilter {
/**
 * 
 */
private XLogger logger = XLoggerFactory
        .getXLogger(CustomLogoutFilter.class.getName());

@Override
protected void doFilterInternal(HttpServletRequest req,
        HttpServletResponse res, FilterChain chain)
        throws ServletException, IOException {

    logger.error("========================================================================================");
    logger.error("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Custom Logout Filter $$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
    logger.error("========================================================================================");

    chain.doFilter(req, res);
}

}

Spring version: 4.1.1 Spring security: 3.2.5

kmansoor
  • 4,265
  • 9
  • 52
  • 95

4 Answers4

39

If you are using Spring Boot, any GenericFilterBean (OncePerRequestFilter is one) in the context will be automatically added to the filter chain. Meaning the configuration you have above will include the same filter twice.

The easiest workaround for this is to define a FilterRegistrationBean in the context, and have it disabled:

<beans:bean id="customLogoutFilterRegistration" class="org.springframework.boot.context.embedded.FilterRegistrationBean">
    <beans:property name="filter" ref="customLogoutFilter"/>
    <beans:property name="enabled" value="false"/>
</beans:bean>

EDIT (11/3/2020):

For anyone working in SpringBoot and wanting to register the bean using annotations. Add the following code in the Spring Boot app initializer file (one with @SpringBootApplication annotation):

@Bean
public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(new YourCustomFilterClassName());
    registrationBean.setEnabled(false);
    return registrationBean;
}
Utkarsh
  • 502
  • 1
  • 5
  • 22
mikeapr4
  • 2,830
  • 16
  • 24
  • 1
    Thank you! Added a similar answer here (after reading this and other answers) - http://stackoverflow.com/a/37904857/1882064 in case it helps clarify this answer for anyone. – arcseldon Jun 19 '16 at 07:22
  • 10
    I wonder why do I have any workarounds for such basic things? Spring becomes over-complicated and counter-intuitive with things like this. – Andreas Gelever Dec 12 '18 at 14:37
10

It is likely being called for other URLs that are being requested. For example, if you have any css, javascript, images that are loaded on the page it will be called for each of those. Try adding a logging statement that displays the current request information to find out if that is the case. For example,

logger.error("URL = " + req.getRequestURL());
Rob Winch
  • 21,440
  • 2
  • 59
  • 76
3

Just sharing my case :(

I wasn't setting authentication.setAuthenticated(true) in the AuthenticationProvider.

Hence, AbstractPreAuthenticatedProcessingFilter called authenticate once, then AbstractSecurityInterceptor was also calling authenticateIfNeeded.

jrhee17
  • 1,152
  • 9
  • 19
0

Spring security has around 12 filters and a few of them try to check if the user is authenticated. For example, there is a filter called AnonymousAuthenticationFilter.

If you are providing your authentication provider and you have authenticated the request once, you should set the authentication object in the security context.

SecurityContextHolder.getContext().setAuthentication(authentication)

In the example, AnonymousAuthenticationFilter tries to get the authentication from the security context. If not found, it will once again make a call again.

Nandlal
  • 7
  • 1