[keycloak-user] Support authorization for dynamic resources not saved in Keycloak resources DB, and querying for additional information from "PIP" service inside of policy

Marcel Német Marcel.Nemet at gmail.com
Mon Sep 10 10:13:24 EDT 2018


It would be great to support dynamic resources using more complex Wildcards
mechanism. It would be very useful for our company. But I will rather
explain the use case on better-known use-case: Groups and Events on
Facebook.



Groups on Facebook have members and admins.  Groups are created and deleted
often, and one user can be member and admin of multiple groups.

Example:

Group for hikers

Admins: Alice, Adam

Members: Mark, Michelle



Group for dancers:

Admins: Antoni

Members: Martin



Admins can create and delete events

e.g. Hiking in Himalayas event

Members can subscribe and unsubscribe from events



The REST API might look like:



GET api/groups/{groupID}/events/

·         Can be done by members or admins



DELETE api/groups/{groupID}/events/{eventID}

·         Only by admins



POST api/groups/{groupID}/events/{eventID}/subscribe

·         Here the danger is that Martin who is not a member of Group for
hikers could manipulate the request and do:

·         POST
api/groups/Group-for-dancers/events/Hiking-in-Himalayas/subscribe

·         So, it is not enough to check whether Martin is a member of the
group in the request. It must also be checked that the Event belongs to
that group.



Or directly, without referencing the group

POST api/events/{eventID}/subscribe

In the second case, the system would have to check whether the user is a
member of the group. This has to be queried from the facebook DB.

POST api/groups/{groupID}/events/{eventID}/unsubscribe



When the user subscribes to an event he can see it under

GET api/user/{userID}/subscribedEvents/{eventID}



And he can unsubscribe under

POST api/events/{eventID}/unsubscribe



==============================



Challenges in Keycloak:

Currently, all the resources would have to be created in the Keycloak
server one by one

E.g.

/groups/Group for hikers/events/Hiking in Himalayas

·         With scopes GET and DELETE

/groups/Group for hikers/events/Hiking in Himalayas/subscribe

/groups/Group for hikers/events/Hiking in Himalayas/unsubscribe



And when the user subscribes to the event, another resource would need to
be added

/user/Mark/subscribedEvents/Hiking in Himalayas

·         With scopes GET

/user/Mark/subscribedEvents/Hiking in Himalayas/unsubscribe

/user/Michelle/subscribedEvents/Hiking in Himalayas

·         With scopes GET

/user/Michelle/subscribedEvents/Hiking in Himalayas/unsubscribe



And when the Mark and Michelle unsubscribe, the last resources should be
removed. This adds additional overhead.



The permissions can be then applied to the resource type if the resources
are properly typed, this works well.



If Keycloak supported dynamic URLs and multiple wildcards or parameters
inside URI

It would be possible to simply define general permissions for the API
routes

For example, it would be great to be able to define a resource with a
wildcard parameter such as

api/groups/{groupID}/events/{eventID}

·         With scope DELETE

Then the permission could be added simply with a policy that permits the
action if the user is admin of the group with ID {groupID}.



Having to create resources in Keycloak resources DB is a drawback because
it creates another single point of failure - we have a complicated system
that is quite critical. Constantly creating and deleting resources is
complicated. If at any time the synchronization between resource DB in
Keycloak and our system fails, it would be very hard to recover.



======================================

At the moment I see a workaround of using different REST API routes such as

DELETE api/groups/events?groupID={groupID}&eventID={eventID}



But this forces us to use sub-optimal paths which do not conform to the
usually recommended syntax of REST APIs.



Then I can define a resource in keycloak as

api/groups/events/*

With scope DELTE



And inside policy enforcer I can push claim such as

"event-delete-claim"="eventID : {request.parameter['eventID']}"

Or even use the whole relative URI as a claim - adding a unique claim to
the RPT makes sure that the user gains access only to single resources or
group fo resources and not to all resources that match api/groups/events/*.





Then in a permission for the resource "api/groups/events/*" with scope
"DELETE" I must check somehow whether the user who is trying to call this
API is admin of a group where the event is hosted. It is hard to know
whether the event belongs to a group from such request since we cannot
trust the information in the HTTP request even if group ID was part of the
request. Here I would need to query the system DB with the eventID and get
the groupID or even better directly list of the admins of the group to
which the event belongs.



=========================================

Summary

·         It would be great to support dynamic resources with multiple
wildcards/parameters so we do not need to sync all existing and newly
created resources with the Keycloak DB

·         It would be great to be able to query external service from
inside of a policy (e.g. something like Java Policy Provider (SPI?) with an
ability to call a trusted Policy Information Point ("PIP") to get
additional information necessary to make a decision)

o    For example, the Policy "Allow if the user is an administrator of the
group of the event" would be applied to the resource "DELETE
api/groups/*/events/*". The policy code would be able to query some backend
service and check that the event really belongs to the group and that the
user is admin of that group.



I would love to hear your thoughts on this, or whether any of the two
propositions could be added or whether another strategy to achieve this
exists.



-- 
Marcel Német
marcel.nemet at gmail.com


More information about the keycloak-user mailing list