Describe the bug HTTP GraphQL call which includes two internal calls to REQUEST and ASYNC dispatchers. Custom Auth filter extending OncePerRequestFilter execute SecurityContextHolder.getContext().setAuthentication(authentication);

REQUEST dispatcher result produce AuthorizationDecision(granted=true) ASYNC dispatcher produces AuthorizationDecision(granted=false) Due to AnonymousAuthorization

Security Config:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@Slf4j
public class SecurityConfiguration {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    val authFilter = new MockAuthorizationFilter();
    val repository = new RequestAttributeSecurityContextRepository();

    http.securityContext((securityContext) -> securityContext
            .securityContextRepository(repository)
        )

        .csrf(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(config -> {
          config.anyRequest().authenticated();
        })
        .addFilterAfter(authFilter, UsernamePasswordAuthenticationFilter.class);
    //WorkAround
   /* http.addFilterAfter(new CustomAuthContextFilter(repository), authFilter.getClass());*/



    return http.build();
  }
}

To Reproduce Run SecurityContextIssueApplication Execute GraphQL call : query DummyQuery { dummyQuery(dummyQueryInput: "12345") }

Expected behavior HTTP status 200 and dummyQuery in GraphQL response: { "data": { "dummyQuery": "DummyGqlResponse" } }

Sample

https://github.com/asndevever/spring-security-auth-context-issue example project

My vision of the problem Bug in SecurityContextHolderFilter

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        if (request.getAttribute(FILTER_APPLIED) != null) {
            chain.doFilter(request, response);
            return;
        }
        request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
        Supplier<SecurityContext> deferredContext = this.securityContextRepository.loadDeferredContext(request);
        try {
            this.securityContextHolderStrategy.setDeferredContext(deferredContext);
            chain.doFilter(request, response);
        }
        finally {
            this.securityContextHolderStrategy.clearContext();
            **this.securityContextRepository.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());** //This line is missing
            request.removeAttribute(FILTER_APPLIED);
        }
    }

Compared with the previous implementation in SecurityContextPersistenceFilter.

Workaround: Added to example commented in config Adding this.securityContextRepository.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse()); call into CustomFilter had resolved the issue with Authentication context propagation between Dispatchers.

Comment From: marcusdacoregio

Hi, @asndevever. If you want to save the SecurityContext you have to explicitly call it in your MockAuthorizationFilter implementation, starting from 6.0, Spring Security does not do it automatically anymore. Take a look at the Session Management section of the docs.