I'm trying to setup a minimal reactive boot app secured with JWT (provided by Keycloak, but not using their resource-server API). Everything went fine with servlet version, but can't figure out what I missed here and there might be a bug (at least error message could be improved)

Boot version is 2.2.4

App output:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.4.RELEASE)

2020-02-12 20:45:27.849  INFO 10768 --- [           main] c.c.s.sample.reactive.ReactiveApp        : Starting ReactiveApp on LAPTOP-JEREM with PID 10768 (C:\Users\jwacongne\dev\workspaces\libs\spring-addons\spring-security-test-keycloack-addons\target\test-classes started by jwacongne in C:\Users\jwacongne\dev\workspaces\libs\spring-addons\spring-security-test-keycloack-addons)
2020-02-12 20:45:27.852  INFO 10768 --- [           main] c.c.s.sample.reactive.ReactiveApp        : No active profile set, falling back to default profiles: default
2020-02-12 20:45:29.179  INFO 10768 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8090 (https)
2020-02-12 20:45:29.191  INFO 10768 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-02-12 20:45:29.192  INFO 10768 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-02-12 20:45:29.352  INFO 10768 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-02-12 20:45:29.352  INFO 10768 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1443 ms
2020-02-12 20:45:30.169  INFO 10768 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-02-12 20:45:30.351  WARN 10768 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration$DefaultConfigurerAdapter': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.annotation.ObjectPostProcessor<?>' available
2020-02-12 20:45:30.352  INFO 10768 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2020-02-12 20:45:30.354  INFO 10768 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2020-02-12 20:45:30.369  INFO 10768 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-02-12 20:45:30.540 ERROR 10768 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean of type 'org.springframework.security.config.annotation.ObjectPostProcessor' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.security.config.annotation.ObjectPostProcessor' in your configuration.

My conf:

@SpringBootApplication(scanBasePackageClasses = { ReactiveApp.class, GreetingHandler.class, GreetingRouter.class,
        MessageService.class, MessageServiceImpl.class })
public class ReactiveApp {
    public static void main(String[] args) {
        SpringApplication.run(ReactiveApp.class, args);
    }

    @EnableWebFluxSecurity
    @EnableReactiveMethodSecurity
    public class ReactiveSecurityConfig {

        @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
        String issuerUri;

        @Bean
        public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
            // @formatter:off
            http.csrf().disable().httpBasic().disable().formLogin().disable();
            http.authorizeExchange().pathMatchers("/secret-endpoint").hasAnyRole("AUTHORIZED_PERSONNEL").anyExchange()
                    .authenticated();
            http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(grantedAuthoritiesExtractor());
            // @formatter:on

            return http.build();
        }

        @Bean
        ReactiveJwtDecoder jwtDecoder() {
            return ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
        }

        @Bean
        public AuthenticationConverter grantedAuthoritiesExtractor() {
            KeycloackOidcIdAuthenticationConverter extractor = new KeycloackOidcIdAuthenticationConverter() {
            };
            return jwt -> Mono.just(jwt).map(extractor::convert);
        }
    }

    private static interface AuthenticationConverter extends Converter<Jwt, Mono<AbstractAuthenticationToken>> {
    }

}

Comment From: snicoll

Thanks for the report. As you are using @ EnableWebFluxSecurity, Spring Boot will not be involved in the configuration of Spring Security. If you believe you have a found a problem with Spring Security's configuration behaviour, please open a Spring Security issue.

Comment From: wilkinsona

@ch4mpy Looking at the logs, you aren't building a reactive app but using the Servlet stack. I can tell this from the fact that a servlet-based application context, ConfigServletWebServerApplicationContext, is being used:

2020-02-12 20:45:30.351  WARN 10768 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration$DefaultConfigurerAdapter': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.annotation.ObjectPostProcessor<?>' available

There may be something that we can do to improve the diagnostics here, but I can't tell without knowing what dependencies your application has. If you can provide us with a minimal sample that reproduces the failure you have shown above, we can see if an improvement is possible.

Comment From: ch4mpy

@wilkinsona thank you for your investigation.

I do have a strange pom with both servlet and reactive depencencies. The reason for that is I want to test / showcase a lib adding enhanced support for resource servers working with Keycloak.

This lib contains implementations for both servlet and reactive resource-servers. So I currently have two different spring-boot apps standing under src/test/java, one being reactive, the other being servlet based.

The only way I see to fix this is splitting my lib in two.

Maybe, trying to setup a reactive boot app within spring-security-test unit-tests is enough to reproduce. I'll give a try later tonight.

Comment From: wilkinsona

The only way I see to fix this is splitting my lib in two.

You can use spring.main.web-application-type=reactive to force the use of the reactive stack when MVC is on the classpath as well.

Maybe, trying to setup a reactive boot app within spring-security-test unit-tests is enough to reproduce. I'll give a try later tonight.

Thanks.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: ch4mpy

I broke my project down to achieve complete separation between webmvc and webflux components

Comment From: mbhave

Thanks for letting us know @ch4mpy.