Describe the bug
I am trying to secure Quarkus backend using Keycloak, following https://quarkus.io/guides/security-keycloak-authorization . I'd like to allow anonymous access for some instances, based on Keycloak configuration. However when I set Policy Enforcement Mode to 'Disabled' in the client, my requests without Authorization header get rejected with 401 Unauthorized.
Note that I want to configure this centrally in KC, not path-specific in application properties. I've tried to change quarkus.keycloak.policy-enforcer.enforcement-mode to PERMISSIVE and it doesn't help; when I set it to DISABLED it gives me (anonymous) correct response.
There's a test for public access but that relies on DISABLED mode for given path.
Expected behavior
Mode 'Disabled' or 'Permissive' with no policy defined should not prevent access of anonymous user.
Actual behavior
Anonymous user gets 401 Unauthorized.
To Reproduce
Follow https://quarkus.io/guides/security-keycloak-authorization and in Client / Authorization set 'Policy Enforcement Mode' to 'Disabled'.
Environment (please complete the following information):
Quarkus 1.0.1.Final, Keycloak 8.0.1
Hi Pedro, please investigate when you get some spare cycles, thanks
On a related matter (without Keycloak Authorization Services), is it possible to grant a role to anonymous user? Say I have @RolesAllowed("spectator") and I want to make this accessible just by adding something like quarkus.security.anonymous.roles=spectator to application.properties? Alternatively can I grant this in KC?
@rvansa No, it is not possible in Quarkus. I'm not sure it should be, how would it differ from PermitAll ?
@rvansa The point here is that the keycloak-authorization relies on the oidc extension and as such it requires a bearer token. That is the reason why you are getting 401.
Currently, you should either disable policy enforcer for the paths you want to make public or trying to use the configuration options from the security layer (https://quarkus.io/guides/security#standard-security-annotations).
The behavior you are looking for makes sense though and we should consider it in the future as an enhancement.
@sberyozkin As I've mentioned, I can imagine some instances of the app allowing read-only access by default, and some requiring authentization even for reading. That's why I'd need to statically define some role - otherwise I could not secure it in the latter type of deployment.
Looks like I have to create the anonymous user and offer anonymous login option in UI.
Hi Pedro @pedroigor , happy to see you being back :-)
I wonder, should we then try to prioritize #4817 (longer-term) ? So that it starts working with all OIDC servers supporting UMA ? Optimizing this extension is fine, but we've added it primarily to support the migration of the existing KC users.
@rvansa So then it would come down to a single JAX-RS method offering a semi-secured access. I'm not sure it is the right solution, the anonymous access is on the specific path, so you can have 2 JAX-RS methods, one serving the anonymous user, one - the authorized one, both delegating to the common implementation.
@sberyozkin I'm not sure if we should prioritize #4817. So far, I see more demand for regular policy enforcement without requiring any of UMA goods.
@pedroigor that is fine, supporting the Keycloak specific policies for the KC users is important. But I think it would be good to say (longer term as I mentioned :-) ) that the users can have something that works for all the supporting OIDCs.
Or am I mistaken that in a way Keycloak Authorization is a Keycloak specific solution to a User Managed Access problem ?
It is specific if you are only using Keycloak as a policy decision point. But when it comes to supporting user-managed access so that users can manage permissions to their resources, then we are a standard based UMA implementation.
Only a very few OIDC implementations support UMA.
@pedroigor thanks, lets chat about UMA later then, perhaps we need to have the users starting opening the concrete issues around it before thinking going further with it in Quarkus...
@sberyozkin Thanks, the 2 endpoints would be viable, though it's a bit PITA to have a switch in frontend.
@rvansa I meant a single JAX-RS endpoint with 2 resource methods. Sorry, not sure I understand the concern. Are you saying you have a path like "/a" which the anonymous users can freely access while at the same time some users may be required to authenticate first before accessing it ? In this case the latter requirement would never be enforceable because anyone can get to this resource publicly anyway.
My use case:
I would like to have "Enter chat" endpoint, where if user have token, it will be identified by it's token user, but if I have no token, then "anonymous" user would be created.
@gintsgints You can have SecurityIdentity injected and check if the request is anonymous or not
@sberyozkin The very point of using Authorization Services is not having anything access-specific in the application, always deciding if it is appropriate to let the user in Keycloak and there only. Once that you start checking SecurityIdentity in the application, this separation is gone.
@rvansa IMHO Having an application with an RBAC method requiring a role which can be accessed by anonymous users is confusing. May be it is only me... Also, I don't think there is anything wrong with checking if the user has actually authenticated or not, it is an orthogonal issue to the policy enforcement
@rvansa The point here is that the
keycloak-authorizationrelies on theoidcextension and as such it requires a bearer token. That is the reason why you are getting401.Currently, you should either disable policy enforcer for the paths you want to make public or trying to use the configuration options from the security layer (https://quarkus.io/guides/security#standard-security-annotations).
The behavior you are looking for makes sense though and we should consider it in the future as an enhancement.
I'm facing this same issue right now. Can you point us where we can disable the policy enforcer for a specific path? I've been looking for it a while and haven't found.
I've also tried to allow access using quarkus' security layer, but it doesn't seem to work when using keycloak's policy enforcer:
%dev.quarkus.http.auth.permission.pagamentos.paths=/pagamentos
%dev.quarkus.http.auth.permission.pagamentos.policy=permit
%dev.quarkus.http.auth.permission.pagamentos.methods=GET
@rinaldodev I guess it should be
quarkus.keycloak.policy-enforcer.paths.foobar.path=/foo/bar
quarkus.keycloak.policy-enforcer.paths.foobar.enforcement-mode=DISABLED
@rvansa you are correct, it does work that way. :)
Thanks a lot!