Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make EnableReactiveMethodSecurity compatible with Kotlin Coroutines #8143

Closed
TonCherAmi opened this issue Mar 18, 2020 · 13 comments
Closed

Make EnableReactiveMethodSecurity compatible with Kotlin Coroutines #8143

TonCherAmi opened this issue Mar 18, 2020 · 13 comments
Assignees
Labels
in: core An issue in spring-security-core type: enhancement A general enhancement
Milestone

Comments

@TonCherAmi
Copy link

Current implementation of PrePostAdviceReactiveMethodInterceptor makes it impossible to use @Pre/PostAuthorize with suspending functions:

// PrePostAdviceReactiveMethodInterceptor::invoke
if (!Publisher.class.isAssignableFrom(returnType)) {
    throw new IllegalStateException("The returnType " + returnType + " on " + method + " must return an instance of org.reactivestreams.Publisher (i.e. Mono / Flux) in order to support Reactor Context");
}

This may be related to spring-projects/spring-framework#22462

Spring boot version: 2.2.1.RELEASE

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 18, 2020
@rwinch
Copy link
Member

rwinch commented Mar 18, 2020

Could you please provide a complete sample?

@rwinch rwinch added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Mar 18, 2020
@TonCherAmi
Copy link
Author

TonCherAmi commented Mar 18, 2020

@rwinch here you go.

Upon making a request,

curl -X POST -v -u admin:qwerty localhost:8080/api/test -d "xzcvxzcv"

an exception is thrown:

{
  "timestamp": "2020-03-18T19:57:41.277+0000",
  "path": "/api/test",
  "status": 500,
  "error": "Internal Server Error",
  "message": "The returnType class java.lang.Object on public java.lang.Object com.example.demo.handlers.TestHandler.test(org.springframework.web.reactive.function.server.ServerRequest,kotlin.coroutines.Continuation) must return an instance of org.reactivestreams.Publisher (i.e. Mono / Flux) in order to support Reactor Context",
  "requestId": "38010f7a-4"
}

Complete stacktrace:

2020-03-18 23:01:43.416 ERROR 5208 --- [oundedElastic-1] a.w.r.e.AbstractErrorWebExceptionHandler : [c3f2d0af-1]  500 Server Error for HTTP POST "/api/test"

java.lang.IllegalStateException: The returnType class java.lang.Object on public java.lang.Object com.example.demo.handlers.TestHandler.test(org.springframework.web.reactive.function.server.ServerRequest,kotlin.coroutines.Continuation) must return an instance of org.reactivestreams.Publisher (i.e. Mono / Flux) in order to support Reactor Context
	at org.springframework.security.access.prepost.PrePostAdviceReactiveMethodInterceptor.invoke(PrePostAdviceReactiveMethodInterceptor.java:76) ~[spring-security-core-5.3.0.RELEASE.jar:5.3.0.RELEASE]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	|_ checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
	|_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
	|_ checkpoint ⇢ HTTP POST "/api/test" [ExceptionHandlingWebHandler]
Stack trace:
		at org.springframework.security.access.prepost.PrePostAdviceReactiveMethodInterceptor.invoke(PrePostAdviceReactiveMethodInterceptor.java:76) ~[spring-security-core-5.3.0.RELEASE.jar:5.3.0.RELEASE]
		at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
		at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
		at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.2.4.RELEASE.jar:5.2.4.RELEASE]
		at com.example.demo.handlers.TestHandler$$EnhancerBySpringCGLIB$$71f7a9a3.test(<generated>) ~[main/:na]
		at com.example.demo.RoutingConfig$routes$1$1$1.invoke(RoutingConfig.kt:21) ~[main/:na]
		at com.example.demo.RoutingConfig$routes$1$1$1.invoke(RoutingConfig.kt:16) ~[main/:na]
		at org.springframework.web.reactive.function.server.CoRouterFunctionDsl$asHandlerFunction$1$1.invokeSuspend(CoRouterFunctionDsl.kt:599) ~[spring-webflux-5.2.4.RELEASE.jar:5.2.4.RELEASE]
		at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ~[kotlin-stdlib-1.3.70.jar:1.3.70-release-328 (1.3.70)]
		at kotlinx.coroutines.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:314) ~[kotlinx-coroutines-core-1.3.4.jar:na]
		at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:26) ~[kotlinx-coroutines-core-1.3.4.jar:na]
		at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:109) ~[kotlinx-coroutines-core-1.3.4.jar:na]
		at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:158) ~[kotlinx-coroutines-core-1.3.4.jar:na]
		at kotlinx.coroutines.reactor.MonoKt$monoInternal$1.accept(Mono.kt:55) ~[kotlinx-coroutines-reactor-1.3.4.jar:na]
		at kotlinx.coroutines.reactor.MonoKt$monoInternal$1.accept(Mono.kt) ~[kotlinx-coroutines-reactor-1.3.4.jar:na]
		at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:57) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:274) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:851) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:203) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:203) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2267) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:137) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:137) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:162) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2075) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1949) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:171) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:171) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4110) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:441) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:211) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:161) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4110) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:141) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilter$FilterSubscriber.onNext(FluxFilter.java:107) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:92) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:274) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:851) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1705) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onNext(FluxDefaultIfEmpty.java:92) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:112) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:287) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:330) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1705) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:112) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2267) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:184) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:103) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:81) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoCurrentContext.subscribe(MonoCurrentContext.java:35) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:112) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2267) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:184) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:162) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:103) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:81) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4110) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:441) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:211) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:161) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4110) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4110) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:78) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2269) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2075) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1949) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Mono.subscribe(Mono.java:4110) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:823) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:589) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:569) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:455) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:289) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:225) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:363) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:161) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1705) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onComplete(FluxDefaultIfEmpty.java:100) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onComplete(FluxMap.java:262) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1706) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.signalCached(MonoCacheTime.java:320) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.MonoCacheTime$CoordinatorSubscriber.onNext(MonoCacheTime.java:337) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:249) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.3.3.RELEASE.jar:3.3.3.RELEASE]
		at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_232]
		at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[na:1.8.0_232]
		at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[na:1.8.0_232]
		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_232]
		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_232]
		at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_232]

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Mar 18, 2020
@rwinch
Copy link
Member

rwinch commented Mar 24, 2020

Thanks for the detailed sample. I don't think this can work at the moment because the ReactiveSecurityContextHolder leverages Reactor's Context which as far as I know requires the return types to be Mono or Flux at this point. Any method that breaks this chain would mean we would not have access to the Authentication and cannot perform any security checks.

@simonbasle Can you comment if Reactor's Context works with (or could work with) Kotlin Coroutines?

@rwinch rwinch added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Mar 24, 2020
@simonbasle
Copy link

IIRC Kotlin Coroutines' have their own concept of context which can be bridged over to Reactor's Context when adapting a Flux/Mono (and should be when using the official bridges IIRC, if that is still a thing). maybe @sdeleuze will have more insight into that.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Mar 24, 2020
@TonCherAmi
Copy link
Author

Interop between coroutine context and Reactor context should be possible according to this issue Kotlin/kotlinx.coroutines#284

@rwinch
Copy link
Member

rwinch commented Mar 25, 2020

Thanks for the additional details @simonbasle and @TonCherAmi We will look into this one once spring-projects/spring-framework#22462 is addressed.

@sdeleuze
Copy link

Indeed we still need to complete the Coroutines story with AOP and annotation based security and transaction support.

@rwinch I will synchronize with you asap we make progress on this issue.

@sdeleuze
Copy link

sdeleuze commented Oct 25, 2020

@rwinch @eleftherias I have just merged @Transactional Coroutines support in Spring Framework (see spring-projects/spring-framework@5429c7a), where the changes should give you some hints about what to do on PrePostAdviceReactiveMethodInterceptor side.

Notice that Coroutines and Reactor conversion is context aware so this is automatically handled, and that you should probably use KotlinDetector.isSuspendingFunction(method) and CoroutinesUtils.invokeSuspendingFunction(...). Make sure to test and support suspending functions returning a Flow which is handled by CoroutinesUtils.invokeSuspendingFunction(...) but could require some extra handling on your side since that a special case that is conceptually equivalent to a Flux.

I don't think updates on Spring AOP side are needed.

@rt-works
Copy link

can still confirm the issue in the spring boot 2.4.1

@danthonywalker
Copy link

Is there a way we can workaround this by implementing our own PrePostAdviceReactiveMethodInterceptor or something? Or do we just have to for now do fun endpoint(): Mono<Any> = mono {}?

@rt-works
Copy link

rt-works commented Feb 15, 2021

@danthonywalker

Is there a way we can workaround this by implementing our own PrePostAdviceReactiveMethodInterceptor or something? Or do we just have to for now do fun endpoint(): Mono<Any> = mono {}?

It didn't really work out, did it? For me the same exception.

@cardechr
Copy link

Has anyone found a workaround for this?

@eleftherias eleftherias added in: core An issue in spring-security-core type: enhancement A general enhancement and removed status: feedback-provided Feedback has been provided labels Apr 9, 2021
@eleftherias eleftherias changed the title EnableReactiveMethodSecurity is not compatible with Kotlin Coroutines Make EnableReactiveMethodSecurity compatible with Kotlin Coroutines Apr 9, 2021
eleftherias added a commit to eleftherias/spring-security that referenced this issue Apr 9, 2021
@eleftherias eleftherias added this to the 5.5.0-RC1 milestone Apr 9, 2021
@6oP
Copy link

6oP commented Apr 21, 2021

@danthonywalker

Is there a way we can workaround this by implementing our own PrePostAdviceReactiveMethodInterceptor or something? Or do we just have to for now do fun endpoint(): Mono<Any> = mono {}?

It didn't really work out, did it? For me the same exception.

Try to remove "suspend" from your endpoint function. mono{} starts new corotine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core An issue in spring-security-core type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

10 participants