18

I have a set a custom authentication filter in my Spring 4 MVC + Security + Boot project. The filter does it's job well and now I want to disable the security for some URI (like /api/**). Here is my configuration:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        webSecurity.ignoring().antMatchers("/api/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.authorizeRequests()
                 .anyRequest().authenticated()
              .and()
                 .addFilterBefore(filter, BasicAuthenticationFilter.class);
    }
}

Unfortunately, when I call a resource under /api/... the filter is still chained. I've added println in my filter and it's written to the console on every call. Do you know what's wrong with my configuration?

UPDATE

Filter code:

@Component
public class EAccessAuthenticationFilter extends RequestHeaderAuthenticationFilter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("FILTER");
        if(SecurityContextHolder.getContext().getAuthentication() == null){
            //Do my authentication stuff
            PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user, credential, authorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }  
        super.doFilter(request, response, chain);
     }

    @Override
    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

}
observer
  • 2,925
  • 1
  • 19
  • 38
rattek
  • 1,650
  • 1
  • 15
  • 28

6 Answers6

44

remove @Component on class EAccessAuthenticationFilter,and like this:

@Override
protected void configure(HttpSecurity http) throws Exception {
   http.authorizeRequests()
             .anyRequest().authenticated()
          .and()
             .addFilterBefore(new EAccessAuthenticationFilter(), BasicAuthenticationFilter.class);
}

https://github.com/spring-projects/spring-security/issues/3958

kimhom
  • 541
  • 4
  • 3
  • 1
    i completley forgot about spring automatically doing filter registration! thank you – billdoor Aug 28 '18 at 07:04
  • 2
    Also check if you have a @Bean annotated method that creates an instance of your E...AuthenticationFilter. I had such a method, I guess Spring added my filter to its filter chain automatically, and NOT in the order I wanted. – chrisinmtown Jul 25 '19 at 21:08
  • 1
    in my case I had to remove `@Bean` annotation from my custom AuthenticationFilter... this ensured that the filter was bypassed for any `web.ignoring()` ant matchers even though the filter was registered on httpsecurity – SourceVisor Aug 17 '19 at 11:36
12

I don't have enough reputation to add a comment, but for anyone like me who was looking for a little more of an explanation for kimhom's answer, WebSecurityConfigurerAdapter will tell Spring Security to ignore any filters added through it. The filter was then still being invoked because the @Component (or any flavor of @Bean) annotation told Spring to add the filter (again) outside of the security chain. So while the filter was being ignored in the security chain, it was not being ignored by the other (non-security?) chain.

This solved two weeks of headaches for me. In my case my custom filter needed the Authentication object given by the SecurityContext where it kept coming up as null because the security chain was never executed.

Machavity
  • 30,841
  • 27
  • 92
  • 100
lancekf
  • 133
  • 1
  • 5
2

I had the correct configuration to ignore some context path in the web security configuration as below..

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/v1/api1").antMatchers("/v1/api2");
}

But I mistakenly had added @PreAuthorize(...) on my controller method and it seems like that method level security was overriding any security configuration set up at the start.

Prashant Rajput
  • 141
  • 1
  • 3
0

I always found the easiest way to do this is to put this configuration in your application.properties:

security.ignored=/api/**
Sahil Chhabra
  • 10,621
  • 4
  • 63
  • 62
Adam
  • 2,214
  • 1
  • 15
  • 26
  • It's security.ignored=/api/** (without "spring") and this solution is not working either. But good to notice! – rattek Aug 25 '16 at 19:06
  • Hmmm, both your original code and this should have worked from my experience. Can you post your relevant filter code? – Adam Aug 25 '16 at 19:10
  • Maybe you can try changing your http security configuration to `http.authorizeRequests().antMatchers("/api/**").permitAll().anyRequest().authenticated()...`, though I don't know why you would need this with your other configuration. – Adam Aug 25 '16 at 19:49
  • Do we have a way to ignore using property file but only for all GET calls. And any other HttpMethod should not be ignored? – Sahil Chhabra Jul 06 '18 at 06:07
0

After few tests I realized that in fact my configurations are ok and it's just a comprehension problem. The spring.security.ignored=/api/** doesn't bypass or turn off the filter. In reality every request still pass through my custom filter, but the difference is that Spring Security doesn't mind of the authentication status nor the granted authority coming from the custom filter.

I was wondering that the "ignored" property simply bypass the spring security filters. It sounds like I was totally wrong...

rattek
  • 1,650
  • 1
  • 15
  • 28
0

I think you also need it in the Filter class as well (extends RequestHeaderAuthenticationFilter) i.e.

public class EAccessAuthenticationFilter extends RequestHeaderAuthenticationFilter {
    public EAccessAuthenticationFilter() {
        super(new RequestMatcher() {
                        RequestMatcher matcher = new AntPathRequestMatcher("/v1/api1");
            return matcher.matches(request);    

        });
    }
}
Michael
  • 1
  • 1