4

I'm working on a spring boot application where I defined my filter to be executed to manage getting and validating the token. So in my Web security class configuration, I managed to do this:

@Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // we don't need CSRF because our token is invulnerable
                .csrf().disable()

                // don't create session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                .authorizeRequests()
                // .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

                // allow anonymous resource requests
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                .antMatchers("/auth/**").permitAll()
                .antMatchers("/places/public").permitAll()

                .anyRequest().authenticated();

        // Custom JWT based security filter
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

        // disable page caching
        httpSecurity.headers().cacheControl();
    }

The authenticationTokenFilterBean is a method annotated with @Bean that returns an instance of my filter:

public class JwtFilter extends OncePerRequestFilter{

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtService jwtService;

    @Value("${jwt.header}")
    private String authorizationHeader;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

        String token = httpServletRequest.getHeader(authorizationHeader);

        String username = jwtService.getUsernameFromToken(token);

        if(username!=null && SecurityContextHolder.getContext().getAuthentication() ==null){
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            if(jwtService.isTokenValid(token, userDetails)){
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

}

Since I'm extending OncePerRequestFilter, this filter is invoked only one time per request which is not the case with GenericFilter that need to be executed one time by the servlet and another time with Spring security.

The problem that I have is that the ant matcher described in my configuration class are also intercepted by the filter even if I permit them with the permitAll() method, I tried to override configure(WebSecurity web) method from WebSecurityConfigurerAdapter and ignore them but still didn't work.

How can I configure Spring security to skip my filter for these requests? I already checked this question Spring Security JWT Filter applies on all requests but it has no solution.

Thank you

Habchi
  • 1,921
  • 2
  • 22
  • 50
  • You can always build another/second configuration without your filter for some URLs. – dur Oct 16 '17 at 20:55

3 Answers3

3

Still handled inside the filter, but cleaner approach. You can override shouldNotFilter(HttpServletRequest request) method of OncePerRequestFilter and based on URL patterns return true to skip filtering.

private static List<String> skipFilterUrls = Arrays.asList("/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js");

@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {

  return skipFilterUrls.stream().anyMatch(url -> new AntPathRequestMatcher(url).matches(request));
}
Ganesh Modak
  • 171
  • 9
1

Change your WebSecurityConfiguration class, it'll look like:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            // we don't need CSRF because our token is invulnerable
            .csrf().disable()

            // don't create session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

            .authorizeRequests()                

            .anyRequest().authenticated();

    // Custom JWT based security filter
    httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

    // disable page caching
    httpSecurity.headers().cacheControl();
}

 @Override
public void configure(WebSecurity web) throws Exception {
    // Ignore spring security in these paths
    web.ignoring().antMatchers("/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js","/auth/**","/places/public");
}

You have to remove the permitAll matchers from HttpSecurity configure method and put it in WebSecurity configure method.

Mikael Boff
  • 183
  • 1
  • 9
-1

I avoid this problem in this way, you can take for reference:

@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws ServletException, IOException {
    if("/login".equals(req.getServletPath()) && "POST".equalsIgnoreCase(req.getMethod())){
        // ......
    }
    filterChain.doFilter(req, res);
}
Dave Pateral
  • 1,415
  • 1
  • 14
  • 21