Skip to content

Retrieving Authentication Information of Reactive Application in JDBC Auditing #2029

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

Closed
kschlesselmann opened this issue Apr 16, 2025 · 5 comments
Labels
for: stackoverflow A question that's better suited to stackoverflow.com

Comments

@kschlesselmann
Copy link

Currently we're trying to migrate our R2DBC application to JDBC because the MSSQL driver seems to be completely unusable. Right now everything looks fine except user auditing information. It seems the the security context information is simply missing if you try to access the ReactiveSecurityContextHolder from a AuditorAware implementation which @EnableJdbcAuditing seem to require.

To wrap our blocking calls we use this simple pattern

Mono.fromCallable { thingRepository.save(Thing()) }
    .subscribeOn(Schedulers.boundedElastic())

and our JDBC configuration looks like

@Configuration(proxyBeanMethods = false)
@EnableJdbcAuditing
class JdbcConfiguration {

    @Bean
    fun auditorAware(): AuditorAware<String> = AuditorAware {
        ReactiveSecurityContextHolder.getContext()
            .map { it.authentication.name }
            .defaultIfEmpty("NOTHING")
            .blockOptional()
    }
}

We've had a look at the reactor context and it seems that it is properly filled in our code but missing in the AuditorAware. Do you have any suggestions how we can bridge blocking auditing with reactive security?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 16, 2025
@mp911de
Copy link
Member

mp911de commented Apr 16, 2025

There's no context propagation imperative and reactive flows. Imperative binds its context to ThreadLocal. With calling blockOptional in AuditorAware, there's no Subscriber context being propagated to ReactiveSecurityContextHolder, hence you don't have access to the original security context.

You would need to build context propagation yourself where you capture security details from the ReactiveSecurityContextHolder in onSubscribe() and clear state upon Publisher completion/failure. It would need to happen after the fromCallable(…) stage and before any subscribeOn() operator to ensure you're running on the same thread.

@kschlesselmann
Copy link
Author

Thanks! Totally makes sense if you think about it.

I came up with

ReactiveSecurityContextHolder.getContext().flatMap { securityContext ->
    Mono.fromCallable { thingRepository.save(thing) }
        .doOnSubscribe { SecurityContextHolder.getContext().authentication = securityContext.authentication }
        .doFinally { SecurityContextHolder.clearContext() }
        .subscribeOn(Schedulers.boundedElastic())
}

and

@Bean
fun auditorAware(): AuditorAware<String> = AuditorAware {
    Optional.of(SecurityContextHolder.getContext())
        .map { it.authentication.name }
}

This seems to work. Is this what you had in mind as well?

@mp911de
Copy link
Member

mp911de commented Apr 17, 2025

Yes, exactly. Please keep in mind that depending on Coroutines threads might still change so that is a rather fragile setup. If it works, then go for it. Can I close this ticket or may I assist you with something else?

@mp911de mp911de added for: stackoverflow A question that's better suited to stackoverflow.com and removed status: waiting-for-triage An issue we've not yet triaged labels Apr 17, 2025
@kschlesselmann
Copy link
Author

kschlesselmann commented Apr 17, 2025

Please keep in mind that depending on Coroutines threads might still change

Could you elaborate a little if/when this will become an issue for us?

Do you know if there is any other work in progress to bridge JDBC and webflux? Looks like r2dbc is not getting much attention sadly :-(

Otherwise thank you very much and yes, I think this can be closed then.

@mp911de
Copy link
Member

mp911de commented Apr 17, 2025

I'm totally unfamiliar with the Coroutine threading model. I can well imagine that when there are other reactive or async components involved that bring their own threads, you might run into thread switches without noticing it.

There's automatic context propagation (see spring-projects/spring-boot#34201) that might help with propagating contextual values across imperative and reactive patterns.

Looks like r2dbc is not getting much attention sadly :-(

This is a consequence of Broadcom now owning our team and companies investing less into OSS. A lot of folks have been let go and so we need to narrow our focus. Also, there isn't much contribution into R2DBC drivers from other folks.

@mp911de mp911de closed this as not planned Won't fix, can't repro, duplicate, stale Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: stackoverflow A question that's better suited to stackoverflow.com
Projects
None yet
Development

No branches or pull requests

3 participants