Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security concurrency control with custom UsernamePasswordAuthenticationFilter

As per the new requirement i have created custom UsernamePasswordAuthenticationFilter to capture additional parameters from the login page. As expected my config was working fine. I'm able to retrieve additional parameters in filter and saving to session. But after adding my custom filter to config, the session management is not working. Previous i was allowing only one session per user by setting max sessions values to 1. It is not working now, application is allowing same user to login multiple times. I'm sure that it is happening only after integrating custom UsernamePasswordAuthenticationFilter to my config. Below is my spring security config.

http.formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login.html")
            .usernameParameter("username")
            .passwordParameter("password")
            .and()
        .logout()
            .logoutSuccessUrl("/login.html")
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout.html"))
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
            .and()
        .sessionManagement()
            .maximumSessions(1)
            .expiredUrl("/multiplesessions.html")
            .sessionRegistry(getSessionRegistry());
        http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);


@Bean
public SessionRegistry getSessionRegistry() {
    return new SessionRegistryImpl();
}
@Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(dsnyUserDetailsService);
    provider.setPasswordEncoder(passwordEncoder());
    auth.authenticationProvider(provider);
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new StandardPasswordEncoder();
}

@Bean(name = "myAuthenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Bean
DsnyUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter() throws Exception {
    DsnyUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new DsnyUsernamePasswordAuthenticationFilter();
    customUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
    customUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login.html", "POST"));

    return customUsernamePasswordAuthenticationFilter;
}

Am i missing any thing here?

like image 899
Srikanth Avatar asked Oct 30 '22 06:10

Srikanth


1 Answers

I resolved this problem by adding custom ConcurrentSessionFilter. Here is the code if any one wants.

    http.sessionManagement().sessionAuthenticationStrategy(concurrentSession());
    http.addFilterBefore(concurrentSessionFilter(), ConcurrentSessionFilter.class);

   @Bean
   public CompositeSessionAuthenticationStrategy concurrentSession() {

            ConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(getSessionRegistry());
            concurrentAuthenticationStrategy.setMaximumSessions(1);
            //concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
            List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<SessionAuthenticationStrategy>();
            delegateStrategies.add(concurrentAuthenticationStrategy);
            delegateStrategies.add(new SessionFixationProtectionStrategy());
            delegateStrategies.add(new RegisterSessionAuthenticationStrategy(getSessionRegistry()));

            CompositeSessionAuthenticationStrategy authenticationStrategy =  new CompositeSessionAuthenticationStrategy(delegateStrategies);
            return authenticationStrategy;
    }

    @Bean
    ConcurrentSessionFilter concurrentSessionFilter() {
            CustomSessionInformationExpiredStrategy redirectStrategy = new CustomSessionInformationExpiredStrategy("/pub/multiplesessions.html");
            CustomConcurrentSessionFilter concurrentSessionFilter = new CustomConcurrentSessionFilter(getSessionRegistry(), redirectStrategy);
            return concurrentSessionFilter;
    }

CustomSessionInformationExpiredStrategy.java

public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

    private Logger log = Logger.getLogger(this.getClass().getName());
    private String expiredUrl = "";

    public CustomSessionInformationExpiredStrategy(String expiredUrl) {
        this.expiredUrl = expiredUrl;
    }

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException {

        log.info("Redirecting to session expired page");
        HttpServletRequest request = sessionInformationExpiredEvent.getRequest();
        HttpServletResponse response = sessionInformationExpiredEvent.getResponse();
        request.getSession();// creates a new session
        response.sendRedirect(request.getContextPath() + expiredUrl);
    }

}

CustomConcurrentSessionFilter.java, no custom code here.

public class CustomConcurrentSessionFilter extends ConcurrentSessionFilter {

    public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry) {
        super(sessionRegistry);
    }

    public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry, SessionInformationExpiredStrategy sessionInformationExpiredStrategy) {
        super(sessionRegistry, sessionInformationExpiredStrategy);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        super.doFilter(req, res, chain);
    }

}
like image 151
Srikanth Avatar answered Jan 02 '23 19:01

Srikanth