kmansoor
kmansoor

Reputation: 4345

Spring security custom filter called multiple times

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

Upvotes: 14

Views: 22555

Answers (4)

mikeapr4
mikeapr4

Reputation: 2856

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;
}

Upvotes: 39

Nandlal
Nandlal

Reputation: 7

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.

Upvotes: 0

jrhee17
jrhee17

Reputation: 1152

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.

Upvotes: 3

Rob Winch
Rob Winch

Reputation: 21720

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());

Upvotes: 10

Related Questions