-
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
Idea for custom permission annotations that can work on user model and endpoint parameters #43238
Comments
/cc @pedroigor (bearer-token), @sberyozkin (bearer-token,jwt,security) |
Thanks @FroMage. Hopefully we'll be able to go ahead with more improvements based on it. Note though, #39663 is only about making it simpler to apply the But I'm positive we'll be able to support custom security annotations even better with your help, cheers |
Hi Steph @FroMage , I think you may be proposing Quarkus own ReBac solution here 👍 |
Oh, I didn't know about that acronym. Relationship-based access control. As opposed to role-based. Yeah, I've never worked on projects where roles-based access control was something that would not come out of relations. |
If I enhanced FWIW I liked idea of |
FYI I'll have a look into this later this week when #43353 is merged (too many merge conflicts). Let's agree on what should be done and thank you for comments so far. |
Just copying an idea from @FroMage here: If Permission had a // frankly I'd get rid of the Permission supertype here, I don't think it does anything for us
public abstract class QuarkusPermission extends Permission {
public abstract boolean isGranted(); // perhaps add SecurityIdentity as parameter?
}
// ...
public class BeanParamPermission extends Permission {
private final String permissionName;
private final String customAuthorization;
private final String userName;
private final String queryParam;
public BeanParamPermission(String permissionName, String customAuthorizationHeader, String name, String query) {
super(permissionName);
this.permissionName = permissionName;
this.customAuthorization = customAuthorizationHeader;
this.userName = name;
this.queryParam = query;
}
@Override
public boolean isGranted() {
boolean queryParamAllowedForPermissionName = checkQueryParams(queryParam);
boolean usernameWhitelisted = isUserNameWhitelisted(userName);
boolean customAuthorizationMatches = checkCustomAuthorization(customAuthorization);
return queryParamAllowedForPermissionName && usernameWhitelisted
&& customAuthorizationMatches;
}
} Then, you can define a default var augmentedIdentity = QuarkusSecurityIdentity
.builder(securityIdentity)
.addPermissionChecker(requiredPermission -> Uni
.createFrom()
.item(requiredPermission.isGranted()))
.build(); Now, if you really insist on keeping
|
Hi @michalvavrik and @FroMage, IMHO it indeed makes sense, to do
It will be a next level development for the authorization layer for sure |
I'll do that. What shall we do about this issue description:
I think once we have |
@FroMage @sberyozkin first thing we need is to agree on API, it doesn't make sense for me to write code before we do. I suggest to continue here: quarkusio/quarkus-security#56 |
This got moved over from #39663 to start a discussion
I think permissions such as "canwrite" that do not have access to what they can write on are fantasy permissions that do not exist in most cases. In most cases permissions need to know who the current user is, and what objects they're expected to work on, in addition to what operation they will do on the object.
Here's a more realistic example of how we could define custom permissions that work on real objects, in a way that makes them composable (I've intentionally cut the permission logic into smaller units so that different endpoints can compose them finer-grained):
There is the problem of figuring out what to do in case for example the project does not exist, which means the permission can't be granted, so we'd get a 401 instead of a 404 that we would be able to do if we did get into the endpoint to check for this before we checked for permissions.
Now, the bigger problem here is the implementation of
ProjectPermission.getProject()
because this is the point where it must access endpoint parameters, and then we get into lots of questions related to transactions, security, deserialisation.The proposed implementation using
RoutingContext
does not work when using Quarkus REST.We could add hooks into Quarkus REST to make it easy to access the endpoint parameters (as they would be passed to the endpoint, so after deserialisation) but that would mean invoking the security check after deserialisation and filters, while ATM I suppose it's checked before. But that would be more useful for security checks. Closer to what one could write in code checks.
Well, it's pretty much required anyway, because we'll need a transaction open to do anything useful, and that's done by the CDI interceptor which currently runs after deserialisation (not sure about filters, have to check).
Anyway. Lots of ways to over-engineer security checks if we want annotations. In my experience, doing checks in code is pretty much always required due to the complexity of expressing this in annotations.
Originally posted by @FroMage in #39663 (comment)
The text was updated successfully, but these errors were encountered: