Is there a way to grab the current authentication/...
# ktor
s
Is there a way to grab the current authentication/principal outside of the context of an Application.call. Would the only way to do this be to store it as a ThreadLocal and implement a ThreadContextElement to copy into appropriate coroutines?
The goal is that my audit code/service layer could just call x.currentPrincipal rather than passing that through all of the layers of the code. Also possibly implementing that myself sounds horribly scary/risky/ill-advised/fun, but feel free to convince me otherwise.
e
How would you be using an application.call outside a route? Don’t your routes call into your service layer?
s
In my route I can do
call.authentication.userPrincipal()
but I want to avoid passing the principal to my service layer explicitly. More or less, I'd like to know who the actor is for any arbitrary repository operation, but don't want to pass that to every service call and then to every repository.
e
Though I don’t recommend it, if you want to do something like you’re saying you may have to create some sort of closure which you call your service methods off of so you can retrieve the user data from it. Something like this (note that I’m not sure this will work):
What I would recommend is adding a route interceptor like I mentioned in another thread: https://kotlinlang.slack.com/archives/C0A974TJ9/p1571237160082100?thread_ts=1566978919.002100&cid=C0A974TJ9 Then, you just retrieve the user data from the call attributes and pass that as a parameter to your service layer
m
If you're using coroutines you don't need a ThreadLocal. Just put it in the coroutine context. However, I suspect this style of global-ish variable will probably lead to sadness eventually.
s
@Evan R. Thanks, but getting the value to pass into the service layer isn't really what I'm looking for. That part's solved. I'm looking to more or less is the behavior of the springSecurityContextHolder or a better understanding of why it's a horrible idea. I agree with @mp that it might/likely will lead to sadness.
m
It becomes a de facto part of the API of your lower level code, except now it's hidden. Refactoring, or just plain old understanding the logic, becomes more difficult because this one (rather important) type of input is not present in the parameter list of your code.
So basically, if you buy the concept that pure functions are easier to reason about, then consider what that says about this approach.
This is also an example of what's called "ambient authority", which is generally something that the security research world is moving away from.
and/or has moved away from 50 years ago but real world systems still use it because UNIX is totally dripping with ambient authority. 😉
s
fair enough. @mp curiously, if i were to put it on the context, how would code that's ignorant of the fact that it's running in a coroutineContext be able to pull variables out of it? Is that possible? (Admitting the same opaqueness of a threadLocal variable)
m
It's not, you'd have to have coroutine aware code (suspending functions) all the way down.
However, the benefit is that unlike thread locals, coroutine context carries over when you spawn new coroutines, unlike when you farm off work into thread pools
s
WIth ThreadContextElement, my understanding is that you can fake that as well
m
Yes, as long as the work you're farming out is done via coroutines.
myExecutor.submit(someRunnable) isn't going to work.
s
ah gotcha
Anyhow.. was trying to avoid 5 lines of code 🙂. Not worth the risk, even if I could get it going. Thanks @mp and @Evan R.