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.