Home > Software design >  Spring Boot 3 with Spring Security Intercepts exceptions I don't want it to
Spring Boot 3 with Spring Security Intercepts exceptions I don't want it to

Time:01-30

I'm building an API using Spring Boot 3.0.2 with Spring Security, I've built out the security filter chain and it's working fine as far as blocking unauthenticated requests. But I have a RestController class that accepts application/json, and if I don't supply the content type header correctly I want the 415 status code returned. Which gets returned fine without Spring Security in the way. But with Spring Security it seems it's being intercepted and returning a 403 instead.

WebSecurityConfig:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
               .cors().and()
               .csrf().disable()
               .authorizeHttpRequests(auth -> auth
                   .requestMatchers("/auth**").permitAll()
                   .anyRequest().authenticated())
               .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
               .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
               .userDetailsService(jpaUserDetailsService)
               .build();
}

Auth Filter:

@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
    private final JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwtToken = request.getHeader(AUTHENTICATION_HEADER);

        if (jwtToken != null && jwtToken.startsWith("Bearer ")) {
            jwtToken = jwtToken.split(" ")[1];
            if (jwtUtils.isValidToken(jwtToken)) {
                UserDetails userDetails = new UserSecurity(jwtUtils.extractUser(jwtToken));
                UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails,
                        null, userDetails.getAuthorities());
                auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }

        filterChain.doFilter(request, response);
    }
}

Rest Controller:

@RestController
@RequestMapping(value = "auth", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class AuthController {
    @GetMapping
    public Object test() {
        Map<String, String> test = new HashMap<>();
        test.put("key", "val");

        return test;
    }
}

Is there a way to only return the 403 exception if it actually is an unauthenticated error? Not for every single exception?

CodePudding user response:

You have to permit the URL /error to see the error.

CodePudding user response:

You have to open the error endpoint, see Spring Boot 2.0 Migration Guide:

Default Security

The security auto-configuration no longer exposes options and uses Spring Security defaults as much as possible. One noticeable side effect of that is the use of Spring Security’s content negotiation for authorization (form login).

Spring Boot 2.0 doesn’t deviate too much from Spring Security’s defaults, as a result of which some of the endpoints that bypassed Spring Security in Spring Boot 1.5 are now secure by default. These include the error endpoint and paths to static resources such as /css/**, /js/**, /images/**, /webjars/**, /**/favicon.ico. If you want to open these up, you need to explicitly configure that.

Your modified security chain configuration:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
               .cors().and()
               .csrf().disable()
               .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/error").permitAll()
                    .requestMatchers("/auth**").permitAll()
                    .anyRequest().authenticated())
               .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
               .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
               .userDetailsService(jpaUserDetailsService)
               .build();
}
  • Related