[keycloak-user] Using Keycloak for per field authorisation

Courtney Robinson courtney.robinson at hypi.io
Mon Aug 13 23:27:52 EDT 2018


On Tue, Aug 14, 2018 at 2:54 AM, Pedro Igor Silva <psilva at redhat.com> wrote:

> Sorry for the late reply ...
>

Not at all. Thank you for the detailed response.

> The other case I mentioned in my first email is where, a user in an
>> organisation has created e.g. a "Book" record. Under default policies only
>> they can see and manage this Book they created. They can then share this
>> book with site 2 so that users in site 2 can also read the book, they may
>> also share it with the whole organisation so anyone in the realm can read
>> it. The extension to this is when members of one site could normally only
>> see a subset of fields from Book but one one occasion a user shares a
>> single Book with one or more members giving then the permission to "manage"
>> this one Book. This lifts the limitation on this one instance of book
>> enabling the user it is shared with to access a field of Book they wouldn't
>> have been able to see before.
>>
>
> Now I see, thanks. I was imagining something like that.
>
> In Keycloak, resource can have a type [1]. A "typed" resource is a
> resource which owner is the resource server (when I say resource server, I
> mean the client application you are setting up permissions). You can define
> permissions to these typed resources [2] where these permissions will be
> considered when deciding whether or not access should be granted to other
> resources with the same type, where these other resources are actually
> instances of the "typed" resource (the class example you gave). Resource
> instances have users as resource owners, not the resource server. That is
> the difference between a typed vs resource instance.
>
> Let's take the case you mentioned as an example. You have a "Book
> Resource" with a type "book" and permissions associated with this book.
> Where policies associated with this permission only grants access to the
> owner of the resource. Once you have this configuration, create a resource
> as follows:
>
> curl -X POST \
>   http://localhost:8180/auth/realms/{realm}/authz/protection/resource_set
> \
>   -H 'Authorization: Bearer {access_token}' \
>   -H 'Content-Type: application/json' \
>   -d '{
> "name":"Alice Book",
> "type": "book",
> "resource_scopes":["read", "manage"],
> "owner":"alice"
>       }'
>
> The command above is creating a book where user "alice" is the owner. Note
> the "type" field defined as "book". Once you do that, if you try to use the
> policy evaluation tool [3] to check permissions for "alice" on resource
> "Alice Book", access should be granted. Note that we did not define any
> permission for "Alice Book" directly, permissions are being processed based
> on what was defined for "Book Resource".
>
> We also allow you to override permissions on a per resource instance
> basis. So, suppose you want to also allow some other user to access "Alice
> Book". You just create a permission for this resource granting access to
> the user you want.
>

Ahhhhh! That example sheds some light on things for me. Thank you for that.


> We also support UMA, a standard focused on privacy and resource sharing
> requirements [4]. We have an extension to UMA (contribution from community)
> that allows resource servers to define custom permissions for user-managed
> resources [5]. When using UMA capabilities, your users are allowed to
> manage their resources via Keycloak Account Service.
>
> [1] https://www.keycloak.org/docs/latest/authorization_servi
> ces/index.html#typed-resources
> [2] https://www.keycloak.org/docs/latest/authorization_servi
> ces/index.html#_permission_typed_resource
> [3] https://www.keycloak.org/docs/latest/authorization_servi
> ces/index.html#_policy_evaluation_overview
> [4] https://www.keycloak.org/docs/latest/authorization_servi
> ces/index.html#_service_user_managed_access
> [5] https://www.keycloak.org/docs/latest/authorization_servi
> ces/index.html#_service_authorization_uma_policy_api
>
>
>>
>>
>>>
>>>
>>> Regarding how the adapter (policy enforcer in particular) work. It
>>> verifies permissions locally in case the client is sending a bearer token
>>> with permissions, otherwise the adapter will query the server for
>>> permissions associated with resource the client is trying to access
>>> (mapping is based on URIs).
>>>
>>
>> I had a feeling. One of the reasons I'm so unclear about how to achieve
>> what we want is that it feels like a mixture of the auth policies Keycloak
>> supports is needed.
>> I've been thinking that for each app, default Keycloak policies are
>> created that e.g. allowed read only within an organisation.
>> Use Keycloak groups to represent "sites" e.g. offices in an organisation
>> and applied default policies to the groups.
>> Then, the key thing I thought was that I'd have to register each type and
>> it's fields in Keycloak as resources and then have a fixed list of scopes
>> read, write, update, delete, share etc
>> When an entry/instance (say of a Book) is shared, the model changes from
>> being type based to being based on the ID of the object i.e. the Book's ID
>>
>
> It makes sense. However, I don't think the model needs to change. Your
> typed resource will always be there. What you need to do is create new
> resources (with their corresponding types) representing those
> "entries/instances".
>

Got it.


>
>
>>
>> If I understood correctly, that means the size of the token will grow
>> with each object shared directly with a user, surely a problem.
>>
>
> Not really. It depends on how you want to enforce ermissions.
>
> If you don't want to evaluate permissions all the time, you can obtain a
> token with some initial permissions. Then you can perform incremental
> authorization to obtain more permissions in addition to those previously
> granted. We also support limiting the number of permissions in a response
> from the server. [4]
>
> In next release, we are also supporting a response_mode parameter that you
> could use to define the format of responses from server. These formats are
> specially useful in case you don't want to use permissions from access
> tokens but invoke server to only obtain permissions.
>
> [4] https://www.keycloak.org/docs/latest/authorization_services/
> index.html#_service_obtaining_permissions
>

We'll have to give this one some careful thought, latency is a big concern.
Some of our customer's use cases demand low latency (automated and pseudo
real time decisions) so in general an approach that minimised round trips
to Keycloak would be best. It's a real mixed bag though because most cases
are web application flows that do not have this low latency requirement.

One of us in the team will be working on this in our next sprint so a lot
of things should fall into place as part of this.


>
>
>> In a similar vein, do I have to create an entry for every Book record in
>> keycloak to be able to do per book permissions?
>>
>
> Yes. You could use a single resource + JS policy too, but there are
> several issues doing that.
>
> People suggested a Resource SPI, which could be used to fetch resources
> from external databases ...
>
>
I take that as suggested but hasn't been done yet? (Given I've not seen the
interface in the codebase or mentioned in the docs) We'd be very interested
in this. Our storage is centred around Apache Ignite and a great deal of
effort's been poured into understanding and working with it. One
outstanding concern with our proposed move to Keycloak for authorisation is
understanding how to scale it well with the rest of our stack.

I've had an attempt at a user SPI and concluded we'd be better off pushing
it to Keycloak backed by Postgres. (Considered if we could write an Ignite
drop in or something similar but the effort wasn't worth the initial
perceived gains since users are probably going to remain relatively small
compared to resources).
Out of interest however, Keycloak's using Hibernate right? How pluggable is
this so that it could be replaced with Hibernate OGM?

For resources this (scaling) is still an open question. We're Kubernetes
based and a base line for our services is to configure it with a minimum
number of replicas and use metrics and auto scalers to grow that based on
usage. Some of my questions may seem odd but as well as the functional
aspect I'm working out how/if this fits in operationally as well.

We have one particular customer with an IoT use case at the moment which
can be quite bursty their entire setup is automated including policies on
who/what can see different pieces of data being produced by devices.
Resource types are relatively fixed in the order of a few thousand,
instances are however hundreds of thousands per hour and can burst to
millions. Those numbers have been steadily growing and we're expecting more
customers with similar or larger numbers.

This is why I was particularly keen to get some answers around whether we'd
have to register every instance in Keycloak, about token size and trips to
Keycloak, we're comfortable scaling ignite and the rest of our stack but
unclear exactly what that means for Keycloak, I've seen and have currently
got an HA Keycloak and Postgres setup and just starting to look into doing
stress tests but figuring out our auto model first since it doesn't make
sense to stress it with one scenario and then implement another!

At the moment some of these things aren't a concern because we use Apache
Shiro in the service so there's no network round trip and our make shift
"policy evaluation" uses the user defined rules that are largely based on
patterns so doesn't need per instance permissions meaning low cardinality
on policy/permissions. With your explanation I now understand how this can
be done but I'm still left with some concern about permission growth for
these automated use cases. Since they're user defined, the slightest
mistake could lead to hundreds of millions of permission entries in
Keycloak in a short space of time. The only solace at the moment is that
the keycloak API isn't being exposed directly so we can probably think of a
way to ensure the flexibility of Keycloak is available while minimising
this explosion of permission entries.

I hope this provides a little more insight and I welcome any further
comments/suggestions on what/where to look to address some of these
concerns or in fact any reason why the concerns are unwarranted.

Regards,
Courtney


More information about the keycloak-user mailing list