Description
Describe the bug
When my custom GrantedAuthority returns null on getAuthority()
, I get the following exception that makes the application fail.
2024-06-13T17:44:59.000+02:00 ERROR 12657 --- [ parallel-2] a.w.r.e.AbstractErrorWebExceptionHandler : [cdb41c64-1] 500 Server Error for HTTP POST "/graphql"
java.lang.NullPointerException: The mapper [org.springframework.security.authorization.AuthorityReactiveAuthorizationManager$$Lambda/0x0000000800d06000] returned a null value.
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:115) ~[reactor-core-3.6.6.jar:3.6.6]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxMapFuseable] :
reactor.core.publisher.Flux.map(Flux.java:6580)
org.springframework.security.authorization.AuthorityReactiveAuthorizationManager.check(AuthorityReactiveAuthorizationManager.java:50)
Error has been observed at the following site(s):
*______________Flux.map ⇢ at org.springframework.security.authorization.AuthorityReactiveAuthorizationManager.check(AuthorityReactiveAuthorizationManager.java:50)
|_ Flux.any ⇢ at org.springframework.security.authorization.AuthorityReactiveAuthorizationManager.check(AuthorityReactiveAuthorizationManager.java:51)
|_ Mono.map ⇢ at org.springframework.security.authorization.AuthorityReactiveAuthorizationManager.check(AuthorityReactiveAuthorizationManager.java:52)
|_ Mono.defaultIfEmpty ⇢ at org.springframework.security.authorization.AuthorityReactiveAuthorizationManager.check(AuthorityReactiveAuthorizationManager.java:53)
*__________Mono.flatMap ⇢ at org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager.lambda$check$2(DelegatingReactiveAuthorizationManager.java:58)
*________Flux.concatMap ⇢ at org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager.check(DelegatingReactiveAuthorizationManager.java:54)
|_ Flux.next ⇢ at org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager.check(DelegatingReactiveAuthorizationManager.java:64)
|_ Mono.defaultIfEmpty ⇢ at org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager.check(DelegatingReactiveAuthorizationManager.java:65)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.authorization.ObservationReactiveAuthorizationManager.lambda$check$4(ObservationReactiveAuthorizationManager.java:70)
|_ Mono.doOnCancel ⇢ at org.springframework.security.authorization.ObservationReactiveAuthorizationManager.lambda$check$4(ObservationReactiveAuthorizationManager.java:76)
|_ Mono.doOnError ⇢ at org.springframework.security.authorization.ObservationReactiveAuthorizationManager.lambda$check$4(ObservationReactiveAuthorizationManager.java:76)
*__Mono.deferContextual ⇢ at org.springframework.security.authorization.ObservationReactiveAuthorizationManager.check(ObservationReactiveAuthorizationManager.java:66)
|_ Mono.filter ⇢ at org.springframework.security.authorization.ReactiveAuthorizationManager.verify(ReactiveAuthorizationManager.java:52)
|_ Mono.switchIfEmpty ⇢ at org.springframework.security.authorization.ReactiveAuthorizationManager.verify(ReactiveAuthorizationManager.java:53)
|_ Mono.flatMap ⇢ at org.springframework.security.authorization.ReactiveAuthorizationManager.verify(ReactiveAuthorizationManager.java:54)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:53)
|_ Mono.doOnError ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:54)
|_ Mono.switchIfEmpty ⇢ at org.springframework.security.web.server.authorization.AuthorizationWebFilter.filter(AuthorizationWebFilter.java:56)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
|_ Mono.onErrorResume ⇢ at org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter.filter(ExceptionTranslationWebFilter.java:53)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
*__________Mono.flatMap ⇢ at org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter.filter(ServerRequestCacheWebFilter.java:41)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
*_____________Mono.then ⇢ at org.springframework.security.web.server.authentication.AuthenticationWebFilter.onAuthenticationSuccess(AuthenticationWebFilter.java:136)
|_ Mono.contextWrite ⇢ at org.springframework.security.web.server.authentication.AuthenticationWebFilter.onAuthenticationSuccess(AuthenticationWebFilter.java:137)
*__________Mono.flatMap ⇢ at org.springframework.security.web.server.authentication.AuthenticationWebFilter.authenticate(AuthenticationWebFilter.java:125)
|_ Mono.doOnError ⇢ at org.springframework.security.web.server.authentication.AuthenticationWebFilter.authenticate(AuthenticationWebFilter.java:127)
*__________Mono.flatMap ⇢ at org.springframework.security.web.server.authentication.AuthenticationWebFilter.filter(AuthenticationWebFilter.java:115)
|_ Mono.onErrorResume ⇢ at org.springframework.security.web.server.authentication.AuthenticationWebFilter.filter(AuthenticationWebFilter.java:116)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
|_ Mono.contextWrite ⇢ at org.springframework.security.web.server.context.ReactorContextWebFilter.filter(ReactorContextWebFilter.java:48)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
|_ Mono.contextWrite ⇢ at org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter.filter(ServerHttpSecurity.java:3968)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.wrapFilter(ObservationWebFilterChainDecorator.java:211)
|_ Mono.doOnSuccess ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$AroundWebFilterObservation$SimpleAroundWebFilterObservation.lambda$wrap$6(ObservationWebFilterChainDecorator.java:367)
|_ Mono.doOnCancel ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$AroundWebFilterObservation$SimpleAroundWebFilterObservation.lambda$wrap$6(ObservationWebFilterChainDecorator.java:368)
|_ Mono.doOnError ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$AroundWebFilterObservation$SimpleAroundWebFilterObservation.lambda$wrap$6(ObservationWebFilterChainDecorator.java:369)
|_ Mono.contextWrite ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$AroundWebFilterObservation$SimpleAroundWebFilterObservation.lambda$wrap$6(ObservationWebFilterChainDecorator.java:373)
*__Mono.deferContextual ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilter.filter(ObservationWebFilterChainDecorator.java:193)
|_ checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.security.web.server.ObservationWebFilterChainDecorator$ObservationWebFilterChain.filter(ObservationWebFilterChainDecorator.java:152)
*__________Mono.flatMap ⇢ at org.springframework.security.web.server.WebFilterChainProxy.filter(WebFilterChainProxy.java:63)
|_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:106)
|_ Mono.doFinally ⇢ at io.sentry.spring.jakarta.webflux.SentryWebFilter.filter(SentryWebFilter.java:39)
|_ Mono.doOnError ⇢ at io.sentry.spring.jakarta.webflux.SentryWebFilter.filter(SentryWebFilter.java:40)
|_ Mono.doFirst ⇢ at io.sentry.spring.jakarta.webflux.SentryWebFilter.filter(SentryWebFilter.java:41)
|_ checkpoint ⇢ io.sentry.spring.jakarta.webflux.SentryWebFilter [DefaultWebFilterChain]
*____________Mono.defer ⇢ at org.springframework.web.server.handler.DefaultWebFilterChain.filter(DefaultWebFilterChain.java:106)
|_ Mono.doOnError ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:84)
|_ Mono.onErrorResume ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:85)
|_ Mono.doOnError ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:84)
|_ Mono.onErrorResume ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:85)
|_ Mono.doOnError ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:84)
*____________Mono.error ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler$CheckpointInsertingHandler.handle(ExceptionHandlingWebHandler.java:106)
|_ checkpoint ⇢ HTTP POST "/graphql" [ExceptionHandlingWebHandler]
*__________Mono.flatMap ⇢ at io.sentry.spring.jakarta.webflux.SentryWebExceptionHandler.handle(SentryWebExceptionHandler.java:70)
Original Stack Trace:
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:115) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainAsync(FluxFlattenIterable.java:453) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:724) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onNext(FluxFlattenIterable.java:256) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2571) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.request(FluxFilterFuseable.java:411) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:241) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:87) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onSubscribe(FluxFilterFuseable.java:305) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:87) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.onNext(FluxPeekFuseable.java:503) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmitScalar(FluxFlatMap.java:492) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:424) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:210) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:335) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:294) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:144) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:373) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:178) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Mono.subscribe(Mono.java:4568) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onNext(FluxConcatMapNoPrefetch.java:207) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:335) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:294) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerComplete(FluxConcatMapNoPrefetch.java:275) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onComplete(FluxConcatMap.java:889) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:189) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onComplete(FluxFilterFuseable.java:171) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.onComplete(FluxPeekFuseable.java:595) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:85) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2573) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2367) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2241) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Mono.subscribe(Mono.java:4568) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:82) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onComplete(FluxFilterFuseable.java:171) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:850) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:612) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:592) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFlatMap$FlatMapMain.request(FluxFlatMap.java:349) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2331) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.request(FluxPeekFuseable.java:437) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2331) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:339) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.request(FluxDefaultIfEmpty.java:98) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.request(FluxPeekFuseable.java:437) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2367) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2241) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:87) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:152) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.onSubscribe(FluxPeekFuseable.java:471) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:152) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.onSubscribe(Operators.java:2051) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2097) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onComplete(FluxDefaultIfEmpty.java:134) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onComplete(FluxFilterFuseable.java:171) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onComplete(FluxMapFuseable.java:350) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1866) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.signalCached(MonoCacheTime.java:337) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onNext(MonoCacheTime.java:354) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:210) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.publisher.MonoPublishOn$PublishOnSubscriber.run(MonoPublishOn.java:181) ~[reactor-core-3.6.6.jar:3.6.6]
at io.sentry.spring.jakarta.webflux.SentryScheduleHook.lambda$apply$0(SentryScheduleHook.java:23) ~[sentry-spring-jakarta-7.9.0.jar:na]
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.6.6.jar:3.6.6]
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.6.6.jar:3.6.6]
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:317) ~[na:na]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
To Reproduce
I can't provide a complete working example but hopefully the following samples will help:
First here is a condensed version of my base security config so that I can work with my permissions provider.
The key points are my asking of the access
authority and that I can return null as a response to getAuthority
which is allowed as per the documentation:
Returns: a representation of the granted authority (or null if the granted authority cannot be expressed as a String with sufficient precision).
@Configuration
class BaseSecurityConfig {
@Bean
fun reactiveJwtAuthenticationConverter() = ReactiveJwtAuthenticationConverter().apply {
setJwtGrantedAuthoritiesConverter { jwt ->
jwt.getClaim<Map<String, List<Map<String, Any>>>>("authorization")
?.get("permissions")
?.let { Flux.fromIterable(it) }
?.flatMap(::permissionToMyAuthority)
?: Flux.empty()
}
}
@Bean
fun filterChain(http: ServerHttpSecurity): SecurityWebFilterChain = http {
csrf { disable() }
formLogin { disable() }
logout { disable() }
httpBasic { disable() }
authorizeExchange {
authorize(anyExchange, hasAuthority("access"))
}
oauth2ResourceServer { jwt {} }
}
}
fun permissionToMyAuthority(permission: Map<String, Any?>) = (permission["scopes"] as List<*>?)
.takeUnless { it.isNullOrEmpty() }
?.let { scopes ->
val rsname = permission["rsname"] as String?
Flux.fromIterable(scopes)
.cast(String::class.java) // We know we only have strings
.map { MyAuthority(it, rsname) }
} ?: Flux.empty()
data class MyAuthority(private val scope: String, private val resource: String?) : GrantedAuthority {
override fun getAuthority(): String? = scope.takeIf { resource == null }
fun hasPermission(scope: String, type: String, reference: String) =
this.scope == scope && nameResource(type, reference) == resource
}
fun nameResource(type: String, reference: String) = "$type:$reference"
It seems that the order in which I process the permissions matter as if it finds the access
authority it won't continue and I won't get the NPE. However if I have my nullable authority first it's going to fail.
Expected behavior
I expect org.springframework.security.authorization.AuthorityReactiveAuthorizationManager#check
to not crash on a null authority and just filter it out.
Code proposition
@Override
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
// @formatter:off
return authentication.filter(Authentication::isAuthenticated)
.flatMapIterable(Authentication::getAuthorities)
.mapNotNull(GrantedAuthority::getAuthority)
.any((grantedAuthority) -> this.authorities.stream().anyMatch((authority) -> authority.getAuthority().equals(grantedAuthority)))
.map((granted) -> ((AuthorizationDecision) new AuthorityAuthorizationDecision(granted, this.authorities)))
.defaultIfEmpty(new AuthorityAuthorizationDecision(false, this.authorities));
// @formatter:on
}