-
Notifications
You must be signed in to change notification settings - Fork 69
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
spring security context not propagated #19
Comments
ok, a first version could be (can be integrated in the project?): const val SECURED_COMMON_POOL = "SecuredCommonPool"
const val SECURED_UNCONFINED = "SecuredUnconfined"
internal open class SpringSecurityCoroutineContext(
private val dispatcher: ContinuationInterceptor
): AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
private var securityContext: SecurityContext = SecurityContextHolder.getContext()
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = dispatcher.interceptContinuation(Wrapper(continuation))
inner class Wrapper<T>(private val continuation: Continuation<T>): Continuation<T> {
private inline fun wrap(block: () -> Unit) {
try {
SecurityContextHolder.setContext(securityContext)
block()
} finally {
securityContext = SecurityContextHolder.getContext()
SecurityContextHolder.clearContext()
}
}
override val context: CoroutineContext get() = continuation.context
override fun resume(value: T) = wrap { continuation.resume(value) }
override fun resumeWithException(exception: Throwable) = wrap { continuation.resumeWithException(exception) }
}
}
internal open class SpringSecurityCoroutineContextResolver: CoroutineContextResolver {
override fun resolveContext(beanName: String, bean: Any?): CoroutineContext? = when(beanName) {
SECURED_COMMON_POOL -> SpringSecurityCoroutineContext(CommonPool)
SECURED_UNCONFINED -> SpringSecurityCoroutineContext(Unconfined)
else -> bean as? CoroutineContext
}
}
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
open class CoroutineContextResolverConfiguration {
...
..
@Bean
@ConditionalOnClass("org.springframework.security.core.context.SecurityContext")
open fun springSecurityCoroutineContextResolver(): CoroutineContextResolver =
SpringSecurityCoroutineContextResolver()
} |
Previous code will not work just because the context is cached by CoroutineMethodInterceptor, so all calls will use the same SpringSecurityCoroutineContext. val contextKey = coroutine.context to coroutine.name
val context = contextMap[contextKey] ?: getContext(contextKey).apply { contextMap[contextKey] = this } so the solution is to capture SecurityContext in the interceptor: Just move private var securityContext: SecurityContext = SecurityContextHolder.getContext() from SpringSecurityCoroutineContext to Wrapper. const val SECURED_COMMON_POOL = "SecuredCommonPool"
const val SECURED_UNCONFINED = "SecuredUnconfined"
internal open class SpringSecurityCoroutineContext(
private val dispatcher: ContinuationInterceptor
): AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> = dispatcher.interceptContinuation(Wrapper(continuation))
inner class Wrapper<T>(private val continuation: Continuation<T>): Continuation<T> {
private var securityContext: SecurityContext = SecurityContextHolder.getContext()
private inline fun wrap(block: () -> Unit) {
try {
SecurityContextHolder.setContext(securityContext)
block()
} finally {
securityContext = SecurityContextHolder.getContext()
SecurityContextHolder.clearContext()
}
}
override val context: CoroutineContext get() = continuation.context
override fun resume(value: T) = wrap { continuation.resume(value) }
override fun resumeWithException(exception: Throwable) = wrap { continuation.resumeWithException(exception) }
}
}
internal open class SpringSecurityCoroutineContextResolver: CoroutineContextResolver {
override fun resolveContext(beanName: String, bean: Any?): CoroutineContext? = when(beanName) {
SECURED_COMMON_POOL -> SpringSecurityCoroutineContext(CommonPool)
SECURED_UNCONFINED -> SpringSecurityCoroutineContext(Unconfined)
else -> bean as? CoroutineContext
}
}
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
open class CoroutineContextResolverConfiguration {
...
..
@Bean
@ConditionalOnClass("org.springframework.security.core.context.SecurityContext")
open fun springSecurityCoroutineContextResolver(): CoroutineContextResolver =
SpringSecurityCoroutineContextResolver()
} |
|
How can I access/configure SecurityContext inside suspend function?
In this example, UserService::changePassword method access to SecurityContextHolder.getContext(): it is null when controller method has the suspend modifier (changePasswordNotWorking) while default method is working (changePassword). I suppose it is also applicable when service has security annotations:
The text was updated successfully, but these errors were encountered: