1

Context: I am building an API using spring, and spring security to protect my endpoints.

What I've tried: I create a WebSecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfig : WebSecurityConfigurerAdapter() {

    @Autowired
    private lateinit var unauthorizedHandler: JwtAuthenticationEntryPoint

    @Qualifier("jwtUserDetailsServiceImpl")
    @Autowired
    private lateinit var userDetailsService: UserDetailsService

    @Autowired
    @Throws(Exception::class)
    fun configureAuthentication(authenticationManagerBuilder: AuthenticationManagerBuilder) {
        authenticationManagerBuilder.userDetailsService<UserDetailsService>(this.userDetailsService).passwordEncoder(passwordEncoder())
    }

    @Bean
    @Throws(Exception::class)
    fun customAuthenticationManager(): AuthenticationManager {
        return authenticationManager()
    }

    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    @Bean
    @Throws(Exception::class)
    fun authenticationTokenFilterBean(): JwtAuthenticationTokenFilter {
        return JwtAuthenticationTokenFilter()
    }

    @Throws(Exception::class)
    override fun configure(httpSecurity: HttpSecurity) {
        httpSecurity.csrf().disable()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/api/user/**").permitAll()
                .antMatchers(
                        HttpMethod.GET,
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter::class.java)
        httpSecurity.headers().cacheControl()
    }
}

My problem: My authenticationTokenFilterBean is getting called on endpoint started by api/user since I am doing ("/api/user/**").permitAll() is this supposed to happen? Because this is calling my JwtAuthenticationTokenFilter (above) and my authToken is always null because I don't pass anything in the Authorization header(since this is an account creation and thats why I put the permitAll in this endpoint ("/api/user/**").permitAll()

class JwtAuthenticationTokenFilter : OncePerRequestFilter() {

    @Qualifier("jwtUserDetailsServiceImpl")
    @Autowired
    private lateinit var userDetailsService: UserDetailsService

    @Autowired
    private lateinit var jwtTokenUtil: JwtTokenUtil

    @Throws(ServletException::class, IOException::class)
    override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
        val authToken = request.getHeader("Authorization")
        val username = jwtTokenUtil.getUsernameFromToken(authToken)

        if (username != null && SecurityContextHolder.getContext().authentication == null) {
            val userDetails = this.userDetailsService.loadUserByUsername(username)
            if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                val authentication = UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.authorities)
                authentication.details = WebAuthenticationDetailsSource().buildDetails(request)
                logger.info("authenticated user $username, setting security context")
                SecurityContextHolder.getContext().authentication = authentication
            }
        }
        chain.doFilter(request, response)
    }
}

Objective: Can someone help me discover if its normal that my authenticationTokenFilterBean is being called on non-protected API. And if it is explain how can I do it. Thanks

José Nobre
  • 739
  • 2
  • 7
  • 16
  • Possible duplicate of https://stackoverflow.com/questions/40475620/spring-security-exclude-url-on-custom-filter – dur Apr 17 '19 at 08:54

1 Answers1

3

A request to an endpoint that's not protected will still go through the entire filter chain, which includes your filter. permitAll() means that the FilterSecurityInterceptor will allow an unauthenticated user to access the endpoint, but does not affect which filters the request goes through.

.antMatchers("/api/auth/**").permitAll() //allow unauthenticated users

If you want your filter to only apply to certain requests, you can add a RequestMatcher that is initialized in your filter's constructor with a certain path to match. For example, new NegatedRequestMatcher(new AntPathRequestMatcher("/api/user/**")) will match any path except your unprotected endpoint. Then in in doFilterInternal() you can do:

if(!requestMatcher.matches(request)) {
    chain.doFilter(request, response);
    return;
}
// ... the rest of your logic

Now your filter will be triggered only when the request is not "/api/user/**" as desired.

NatFar
  • 2,090
  • 1
  • 12
  • 29