1

Given following filter chain:

@Bean
@Order(0)
public SecurityFilterChain securityFilterChain(
      HttpSecurity http,
      @Qualifier(OpaqueTokenAuthorizationFilter.OPAQUE_TOKEN_AUTHORIZATION_FILTER)
          OncePerRequestFilter authorizationFilter
  )
 http
            .authorizeHttpRequests()
            .anyRequest()
            .authenticated()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilterBefore(authorizationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();

And a OncePerRequestFilter like this:


@Component(OpaqueTokenAuthorizationFilter.OPAQUE_TOKEN_AUTHORIZATION_FILTER)
@Order(Ordered.HIGHEST_PRECEDENCE)
@RequiredArgsConstructor
public class OpaqueTokenAuthorizationFilter extends OncePerRequestFilter {

  public static final String OPAQUE_TOKEN_AUTHORIZATION_FILTER =
      "OPAQUE_TOKEN_AUTHORIZATION_FILTER";

  @Override
  protected void doFilterInternal(
      HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws IOException, ServletException {
    // Note it always registers autnetication in context
    var auth =
        UsernamePasswordAuthenticationToken.authenticated(
            "test", null, List.of(new SimpleGrantedAuthority("TEST")));
    auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
    SecurityContextHolder.getContext().setAuthentication(auth);
    filterChain.doFilter(request, response);
  }
}

All of the requests fail in Authorization filter because SecurityContextHolder returns anonymous authentication when a generic endpoint is being hit. It is being thrown by ObservationDecisionManager during the decision check (because the authentication object is anonymous).

The custom filter executes and sets authentication.

Is there anything else needed for the new Spring Security configuration?

Alisher
  • 480
  • 5
  • 16
  • any reason you are adding your filter after the UsernamePasswordAuthenticationFilter and not before? Also the default auth is basic and you haven't set up form auth explicitly (I don't think that might matter for your case though) – Neeraj Jan 22 '23 at 18:15
  • No particular reason, I was experimenting a lot; trying to figure out why this configuration not working. It was actually set before UsernameAuthenticationFilter. I will update sample – Alisher Jan 22 '23 at 21:00
  • 1
    Can you try to remove your @Order(Ordered.HIGHEST_PRECEDENCE) from the filter. Without that annotation everything works as expected. I don't have the reasoning though why it is messing up the filter chain and i guess triggering a different flow.. – Neeraj Jan 23 '23 at 19:26
  • That's very strange but it did resolve the issue. Without the order annotation, it does indeed work. But I wonder if there is a reasonable explanation for this. – Alisher Jan 23 '23 at 20:01

1 Answers1

1

If you debug the order in which spring security filter chain is invoked in your case it seems adding @Order annotation causes it to run before FilterChainProxy starts its processing logic and then it sets the SecurityContext to empty inside SecurityContextPersistenceFilter which overwrites what you set in your filter causing the behavior you see. Since you are trying to add a custom auth mechanism it would be recommended to add the filter before UsernamePasswordAuthenticationFilter which your SecurityFilterChain does but seems to be overridden by @Order annotation. I guess the Order annotation is redundant in this case anyway and should be removed.. See this post on more details on how the chain is invoked - link

You can play around by setting the debug level logging of spring security to see how these filters are invoked.

logging.level.org.springframework.security=DEBUG
Neeraj
  • 228
  • 1
  • 6