We understand that we can use keycloak to fully implement authorization for our application. We would love for a keycloak administrator to create resources for the URIs in our backend API application, and then assign the appropriate permissions to users as they choose per their requirements, which may change over time, such that we would not have to update application code when security requirements change. We believe that we would ultimately have to implement more code on the app side if we used role-based access control. We have a frontend app, written in react, and a backend app, written in python. We have two clients set up under the same realm in keycloak, one for the frontend and one for the backend. The frontend client is public, and we learned that we can do a token exchange in order to access certain keycloak APIs using the more extensive permissions of the backend app client.
We were trying to figure out how to implement URI-based access controls, and we stumbled upon an example application on the internet that was purporting to do this. We couldn't figure out how it was doing it, so we used tcpdump to watch the network traffic while it provided access to certain users and denied access to others to certain URI paths. We discovered that it was using the resource_set path in keycloak, which is described in the spec at
https://docs.kantarainitiative.org/uma/rec-oauth-resource-reg-v1_0_1.html and documented to some degree at
https://github.com/keycloak/keycloak-documentation/blob/main/authorization_services/topics/service-protection-resources-api-papi.adoc, though there are some parameters that keycloak supports that are not listed here.
The scenario we are trying to implement as a proof of concept is to have two resources, /* and /blog/post/1, and two users, ciadmin1 and repeat_form_user_1. ciadmin1 is assigned to a role that gets access to everything (/*) via a permission/policy. repeat_form_user_1 is assigned to a role that gets access to /blog/post/1 via a permission/policy. Since ciadmin1 has access to /*, we would expect that when ciadmin1 hits /blog/post/1, the result would be PERMITTED, but it is not, because the /resource_set keycloak API endpoint (which returns an array of resources) returns only the resource corresponding to /blog/post/1 when we ask it for the same URI, rather than ALSO returning the resource corresponding to /*. If /resource_set does not return /*, our app has no way of determining that the ciadmin1 user SHOULD have access to the URI in question. The summary of what is happening is described by the output of a script we wrote to replicate this scenario:
ciadmin1, /blog/post/1, DENY
ciadmin1, /blog, APPROVED
repeat_form_user_1, /blog/post/1, APPROVED
repeat_form_user_1, /blog, DENY
All of this is per our expectation except that we would also expect ciadmin1 /blog/post/1 to be APPROVED. You can run the script like this:
git clone
https://gist.github.com/9adec79ae922420d25cd4a6026bd9ae9.git && cd 9adec79ae922420d25cd4a6026bd9ae9 && chmod +x replicate_resource_set_denied_based_on_uri && ./replicate_resource_set_denied_based_on_uri
We could work around this issue by:
* assigning an additional policy to the permission that grants access to /blog/post/1
* updating the /* everything resource to have it include /blog/post/1 in addition to /*
Both of these feel like brute force solutions, and they would involve additional work for EVERY new fine-grained permission that we wanted to add. It seems like an admin should not lose access to /* just because a more specific resource URI is mentioned in a different permission.
Are we doing something wrong? Is this a keycloak bug, and should it actually return ALL relevant resources when we ask it for /realms/testing/authz/protection/resource_set?matchingUri=true&deep=true&max=-1&exactName=false&uri=[escaped /blog/post/1 path] ? Thanks!