Keycloak URI-based fine-grained authorization with resource set UMA API

1,222 views
Skip to first unread message

Jason Lantz

unread,
Jul 14, 2022, 5:32:43 PM7/14/22
to Keycloak User
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!

Björn Pedersen

unread,
Jul 15, 2022, 5:03:35 AM7/15/22
to Keycloak User

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!

Jason Lantz

unread,
Jul 18, 2022, 4:21:22 PM7/18/22
to Keycloak User
Hey thanks for the response but I'm not sure that's it. The problem we are having seems to come from the resource_set endpoint specifically where it only returns the first matching resource it finds. The lines in question are possibly https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java#L421-L423 since it only does the pattern matching with the uri if the resource is not found and https://github.com/keycloak/keycloak/blob/main/common/src/main/java/org/keycloak/common/util/PathMatcher.java#L122 where it returns an exact path match if found.
Reply all
Reply to author
Forward
0 new messages