Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different filters for different url patterns

I have a spring boot application that provides mainly REST endpoints, authentication is done via token (sent in Authorization header) where I have my own TokenAuthenticationFilter added before LogoutFilter to set the security context.

In the process of creating an admin console, I want admin authentication to be separate from regular users, as I'm not sharing tables between Admins and Users for several reasons, on the database level I have the following user,user_token,admin,admin_token. So in order to accomplish this, I thought of several solutions:

  1. Let the current TokenAuthenticationFilter handle user/admin token auth. This however will require to either: Modify the filter to determine whether it's an admin or a user token based on url pattern (so for example if it's /admin/**, the filter will know which service to call) or have the admins header unique from the users (i.e. User sends U-Auth header, Admin sends A-Auth header) and the filter will act based on header name. This all doesn't sound good to me.
  2. Specify a set of filters to apply per url pattern, for example /admin/** will have AdminTokenAuthFilter added to the chain, while any other pattern will have the old TokenAuthenticationFilter in the chain. This sounds better than the earlier approach but I'm having trouble to implement it. I tried to register my own FilterRegistrationBean inside my WebSecurityConfigurerAdapter

Example:

 @Bean
 public FilterRegistrationBean adminFilter(){
     FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
     filterRegBean.setFilter(new AdminTokenAuthFilter());
     List<String> urlPatterns = new ArrayList<>();
     urlPatterns.add("/admin/*");
     filterRegBean.setUrlPatterns(urlPatterns);
     return filterRegBean;
 }

This seems to work but I'm unsure if it's proper practice also I'm concerned about one thing, I found that this adds the filter to the springs originalChain of filters, not to the additionalFilters that seems to apply when adding filters regularly in my WebSecurityConfigurerAdapter using http.addFilterBefore(tokenAuthenticationFilter, LogoutFilter.class). I don't want to alter springs original filter chain, i'd rather have my custom filters in the additional filter chain. Can anyone elaborate on this please?

  1. Create two separate dispatcher servlets and make each one listen to a specific url pattern and I suppose each dispatcherServlet will have its own security configuration.

Can anybody share some knowledge on what's the best approach in such a scenario?

like image 936
prettyvoid Avatar asked Sep 03 '25 04:09

prettyvoid


1 Answers

Ended up writing two security configurations, the first one applies to a specific antmatcher, the second one is for any other url pattern. Like so:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = "x.x.x")
public class NewSecurityConfiguration {
    @Configuration
    @Order(1)
    public static class BackendSecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Autowired CustomSystemUserDetailsService customSystemUserDetailsService;
        @Autowired SystemTokenAuthFilter systemTokenAuthFilter;
        @Autowired CustomLogoutFilter customLogoutFilter;
        @Autowired UnauthorizedEntryPoint unauthorizedEntryPoint;

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

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

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {                
            auth.userDetailsService(customSystemUserDetailsService).passwordEncoder(passwordEncoder());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {    
            http.antMatcher("/system/**")
                    .addFilterBefore(systemTokenAuthFilter, LogoutFilter.class)
                    .addFilterBefore(customLogoutFilter, LogoutFilter.class)
                    .authorizeRequests()
                    .antMatchers("/system/login").permitAll()
                    .anyRequest().authenticated()
                    .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint)
                    .and()
                    .httpBasic().disable()
                    .csrf().disable()
                    .logout().disable();
        }
    }

    @Configuration
    @Order(2)
    public static class FrontEndSecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .addFilterBefore(userTokenAuthFilter, LogoutFilter.class)
                    .addFilterBefore(customLogoutFilter, LogoutFilter.class)
                    .authorizeRequests()
                    .antMatchers("/access/*").permitAll()
                    .antMatchers("/ref/*").permitAll()
                    .antMatchers("/ticket_parser/*").permitAll()
                    .antMatchers("/reset_password/**").permitAll()
                    .antMatchers("/link_profile/**").permitAll()
                    .antMatchers("/email_verification/**").permitAll()
                    .antMatchers("/ref").permitAll()
                    .antMatchers("/flightstats/alert").permitAll()
                    .antMatchers("/airline/list").access("authenticated or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
                    .antMatchers("/airport/list").access("authenticated or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
                    .and()
                    .authorizeRequests().anyRequest().authenticated().and().authorizeRequests()
                    .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint)
                    .and()
                    .httpBasic().disable()
                    .csrf().disable()
                    .formLogin().disable()
                    .logout().disable();
        }
    }
}
like image 91
prettyvoid Avatar answered Sep 05 '25 01:09

prettyvoid