-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Offer a way to block inside custom SecurityContext.isUserInRole
with resteasy-reactive
#38940
Comments
/cc @FroMage (resteasy-reactive), @geoand (resteasy-reactive), @sberyozkin (security), @stuartwdouglas (resteasy-reactive) |
@JChrist Hi, can you clarify one point please,
The current security context represents an individual authenticated identity, a user, with one or more roles, but a single user would not have a big number of roles. Can you clarify why you can't load roles specific to the current user only at the security context creation time ? |
For my specific use-case, the number of available roles to each user can be in the thousands and behind the scenes, |
@JChrist Can you issue a query to the DB where the query only checks if the roles listed in |
@sberyozkin as I tried to explain, this could be a solution, but the total number of roles listed in |
@JChrist Sure, but in context of the specific JAX-RS method invocation, there is only one or very few roles configured in It looks like that this is more or less what you'd like to do anyway but from Do you think what I'm suggesting is totally different to what you are proposing ? |
Oh, sorry, now I understood your suggestion! |
@JChrist Np, thanks for clarifying. Is there any particular reason you prefer to do it at the pre-matching time ? |
@sberyozkin no, not really. Just that I couldn't make it work any other way. My tests showed that my normal (i.e. not pre-matching) filter would not even be reached otherwise. |
@JChrist Right, please consider creating a small reproducer related to the post-match filter not reached, sounds like it should work so if it does not for any obvious reasons there might be a bug lurking somewhere. |
Hi @sberyozkin, I also see in the documentation a notice about using pre-matching for custom security context here: https://quarkus.io/guides/security-customization#jaxrs-security-context |
Hi @JChrist
Sorry I forgot about it. Hmm... What I'm surprised though is that the filter is not reached at all, if it were reached then maybe we could update the CurrentIdentityAssociation directly. Can you please give me a favor and check a couple of things: 1) can you just try Perhaps another option is to use a pre-match filter but instead of @michalvavrik, if you have any other ideas, please comment |
This works as I expected. I can't react all that is written (there is too much of it), but I run your tests:
Your tests are passing if you do not require resource match (I'm sure you know that, but just that we have same starting point), that is with this patch:
Which means your only problem is that you want to enhance identity based on the resource match. That can be done in Quarkus 3.9 (and 999-SNAPSHOT as it requires #38772), please see that resource method is available and identity is augmented:
Which reminds me I'll need to improve JAX-RS HTTP perms docs as I'm worried people using it like this without more info. It will only work for endpoints secured with RBAC or Anyway, I hope this solves your problem and let me know if I missed something. |
@sberyozkin if being able to access matched resource method during security augmentation is of interest, I could tweak JAX-RS HTTP permissions little so that they can be used for this augmentation in all cases, because now you can only use them in one of following cases:
We could add some config property that would always enable it. However I have certain doubts this is common requirement, isn't this rather edge scenario? Maybe what we have is already enough (+docs improvements). |
@michalvavrik Oh, cool, that is a great thing that you can now inject By the way, the reason I was surprised the post match filter was not reached was because I recall at some point an anonymous identity was created when no security extensions were available, but then I checked and saw smallrye-jwt in the pom... Thanks for the super fast feedback |
Hi @sberyozkin, |
This code, from Quarkus-WebAuthn supports blocking calls as part of security on the IO thread, here's how it's done: @SuppressWarnings({ "rawtypes", "unchecked" })
private <T> Uni<T> runPotentiallyBlocking(Supplier<Uni<? extends T>> supplier) {
if (BlockingOperationControl.isBlockingAllowed()
|| isNonBlocking(userProvider.getClass())) {
return (Uni<T>) supplier.get();
}
if (isRunOnVirtualThread(userProvider.getClass())) {
return Uni.createFrom().deferred(supplier).runSubscriptionOn(VirtualThreadsRecorder.getCurrent());
}
// run it in a worker thread
return vertx.executeBlocking(Uni.createFrom().deferred((Supplier) supplier));
}
private boolean isNonBlocking(Class<?> klass) {
do {
if (klass.isAnnotationPresent(NonBlocking.class))
return true;
if (klass.isAnnotationPresent(Blocking.class))
return false;
if (klass.isAnnotationPresent(RunOnVirtualThread.class))
return false;
klass = klass.getSuperclass();
} while (klass != null);
// no information, assumed non-blocking
return true;
} That should help you :) |
You can use this to fetch your user roles from a DB within the security layer, when creating the identity. |
Hi @FroMage and thanks for the input! |
I'm sorry, but I don't understand this part. I thought I explained both why your resource is What I mean is: there can't be better way for reasons explained in previous comment in detail. And BTW my suggestion returns Only thing is that I waited for @sberyozkin for advertised feedback before making this general solution (meaning -> allow using JAX-RS HTTP perms without
@FroMage should maybe https://github.com/quarkusio/quarkus/blob/main/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/security/VertxBlockingSecurityExecutor.java use |
Hi @michalvavrik! |
np, I'll use this issue eventually (might take few weeks before I get to it) to document this and improve it.
You need to remember the order of things - your It would be easier to look at the code, e.g. if you provided updated reproducer, however I will try to answer step by step:
I would expect that if you remove your filter and leave the default one
I can't see any connection between these 2, how one could affect the other. It would be bug provided you are sure about this. If so, please provide a reproducer. My first thought would be whether you activate CDI request inside that pre-match filter and in what fashion.
Absolutely, don't do that. You can either use custom JAX-RS SecurityContext in pre-match phase or JAX-RS HTTP Security Policy that will have the resource available. You can use both, but remember the order. |
I have now updated the sample code to include the HttpSecurityPolicy. |
Right, it's null because the resource info is request scoped bean and you create it during pre-match when it's still null (it's injected in that filter as well...). By no means I'm authority on this, but FWIW not a bug. Just don't create the bean during pre-match.
Because identity augmented by HTTP Permissions is not reflected in the JAX-RS SecurityContext. In other words, we do synchronize it, but before it happens. That's a bug, I'll fix that. TL;DR; @JChrist you scenario is legit, but we need little tweaks for it. I'd rely on the |
To stay safe, I suggest to wait for the fix. |
Ask @cescoffier |
No, it should not use the virtual thread scheduler. The virtual thread scheduler makes a best-effort approach to return to the worker thread pool; however, there are subtle differences, and it was only made for methods annotated with @RunOnVirtualThread (which is not your case here). |
Understand, thank you for your time @cescoffier . |
Description
When using resteasy-reactive and creating a custom SecurityContext, attempting to block inside
isUserInRole
is forbidden, e.g. for looking up a specific role requested with@RolesAllowed
in the database.Unfortunately, there is currently no (easy) way to overcome this situation, since, even if the resolved endpoint containing the
RolesAllowed
annotation is blocking, the check will happen on an IO thread.The only workaround I have found so far, is to check inside
isUserInRole
if blocking is allowed, withBlockingOperationControl.isBlockingAllowed()
. If not, then return true, so that the request is not rejected immediately and add a@ServerRequestFilter
(allowed to block) that injectsResourceInfo
, checks if there areRolesAllowed
annotations present in the matched endpoint and actually perform the role check.I have created an example project with this: https://github.com/JChrist/quarkus-blocking-roles
While this example is trivial to resolve, by not needing to block to check the role, let's assume that in a real-world scenario that wouldn't be the case, e.g. in the case where the number of roles would be too many to pre-load.
Ideally, I would like for a way to instruct quarkus that this check is performed after the request is offloaded to a worker thread. I understand that this means that all requests would need to become blocking, but as things stand, even if all requests are blocking, this check still happens on IO thread.
Implementation ideas
No response
The text was updated successfully, but these errors were encountered: