-
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
Improve Security events by assuring we add identity and RoutingContext whenever available and help to locate security check with secured method property #40723
Conversation
if (event != null) { | ||
|
||
if (event.user() instanceof QuarkusHttpUser user) { | ||
return Map.of(RoutingContext.class.getName(), event, SecurityIdentity.class.getName(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is SecurityIdentity
needed ? It is already available in https://github.com/quarkusio/quarkus/blob/main/extensions/security/runtime-spi/src/main/java/io/quarkus/security/spi/runtime/AbstractSecurityEvent.java#L19
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have good eyes, this is the weakest place of this PR and I wasn't sure how to deal with it.
- In Quarkus Security I cannot take the identity from
RoutingContext
. - Inside
SecurityConstrainer
, I cannot call:
https://github.com/quarkusio/quarkus/blob/main/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityIdentityAssociation.java#L62 because it would trigger authentication. - I cannot add a new method like
SecurityIdentityAssociation#getIdentityIfPresent
, because visibility would have to bepublic
(it's different package) and I wonder if it would confuse users [though IMHO they must use CurrentIdentityAssociation in order to program against interface].
so the identity must come from Vert.x HTTP. I put it to the properties and I absolutely agree it's strange to have the identity in properties only in this scenario.
- The easiest way would to to simply remove it before creating the event somewhere around here (outside that IF):
Line 132 in aeba22d
identity = (SecurityIdentity) additionalEventProps.get(SecurityIdentity.class.getName()); - if that is not acceptable, I would require a new runtime SPI class, which I tried to avoid because users work with the SPI (reproducer of this issue works with AbstractSecurityEvent); plus it's one extra class to metadata space that can be avoided
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicating SecurityIdentity
as one of the event properties is not a big problem.
What I don't understand is this: HttpAuthorizer
already fires authorization failure events if the access was denied, and there it includes the identity, so, what case does this PR cover ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicating
SecurityIdentity
as one of the event properties is not a big problem.
cool, that was my thinking
What I don't understand is this:
HttpAuthorizer
already fires authorization failure events if the access was denied, and there it includes the identity, so, what case does this PR cover ?
Unsecured JAX-RS resources that calls CDI beans with standard security annotations. Inside JAX-RS endpoint you will never be able to statically analyze what CDI beans are going to be invoked (it depends on business logic).
If you want, you can have a look into the tests for it, it's the one called testNestedRolesAllowed
and testNestedPermitAll
, but I can also describe it for you. What is happening is that CDI beans are secured by CDI interceptors. and the CDI interceptors are inside Security extension that is not based on the Vert.x. In #40170 (comment) user described that they have requirement to log some actions for security audit and inside the issue description #40170 he says When a method (as opposed to a REST resource) is annotated with an RBAC annotation ..., please have a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it because the security events are not always covered at the HttpAuthorizer
(quarkus-vertx-http-level
) level only and sometimes at the quarkus-security
level ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it because the security events are not always covered at the
HttpAuthorizer
(quarkus-vertx-http-level
) level only and sometimes at thequarkus-security
level ?
Yes, same as authorization. I can be even more specific:
@ApplicationScoped
public class SecuredBean {
@RolesAllowed("admin")
public String sayAdmin() {
return "admin";
}
}
In this example, the SecuredBean#sayAdmin
is secured by CDI interceptor, not the HttpAuthorizer
. It is not possible to use the HttpAuthorizer
because the authorizer is for HTTP request, but this is method chain invocation. In other worlds, you do not know that SecuredBean#sayAdmin
is going to be called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to update AbstractSecurityEvent.getSecurityIdentity
to check the properties if the identity property is null ? Otherwise we'd need to recommend users in the docs that you have to check both getIdentity
and properties which may be a bit confusing for users
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to update
AbstractSecurityEvent.getSecurityIdentity
to check the properties if the identity property is null ? Otherwise we'd need to recommend users in the docs that you have to check bothgetIdentity
and properties which may be a bit confusing for users
I didn't think of this solution. What I did here
Line 132 in aeba22d
identity = (SecurityIdentity) additionalEventProps.get(SecurityIdentity.class.getName()); |
io.quarkus.security.spi.runtime.AbstractSecurityEvent#securityIdentity
, this way, AbstractSecurityEvent.getSecurityIdentity
works (I have it tested).
What you suggest would work as well. I am open to changing it if you prefer that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What you did looks better as it can only happen on this security constrainer path
Status for workflow
|
Thank you @michalvavrik , @sberyozkin ! 👍 |
This looks more like a new feature than a bugfix. It's more involved than I feel comfortable to backport. |
fixes: #40170
Changes:
@RolesAllowed({"user", "admin"})
and dynamically resolved bean requires@RolesAllowed("admin")
SecurityConstrainer
a synthetic bean, I also improved runtime config detection so that we avoid synchronized block when possible (that's just few lines)