Alternative approach for restricting access to clients based on roles

332 views
Skip to first unread message

Thomas Darimont

unread,
Apr 15, 2020, 7:28:03 PM4/15/20
to Keycloak Dev
Hello,

there are currently a few ways to prohibit logins to certain clients for users with certain roles on the keycloak site
- authorization services? -> Could never make this work 
- custom authenticator implementation -> logic can be kept quite simple for most cases, but this functionality is needed quite often...

Therefore, I played with an idea I had in my head for quite some time already: an authenticator which can evaluate a generic access-policy DSL specified in JSON format.

This introduces a new Authenticator with the name "Check Access Policy" which be used in custom authentication flows after the user has authenticated but before the authentication flow has completed.
Depending on the outcome of the access-policy check the login / access to a client is allowed or rejected.

An access-policy can be defined as a JSON document which holds a list of access-policy entries. An access-policy-entry consists of a client-id regex pattern "app" and a list of allowed realm- or client-role names. Client roles have the form "clientId.roleName".
Note that the "app" regex pattern can contain capture groups which can be referenced in the role names.

If a client is not contained in the access-policy the access to this client is always granted. If a client is contained in the access-policy, but contains an role list with the sole value NONE, then access is always denied.

An example access-policy looks like this:

E0) Exmaple for explicitly allowing and denying access based on roles

Users with role role1 or role2 can access the client clientId1. No user can access the client with clientId2.
{"p":[
    { "app": "clientId1", "allow": ["role1","role2"] },
    { "app": "clientId2", "allow": ["NONE"] }
]}

# Additional Access Policy Examples

E1) Explicitly allow access to clients for some roles
Users with role user or admin can access the client test-client. Users with role admin can access the client admin-client.

{"p":[
    { "app": "test-client", "allow": ["user", "admin"] },
    { "app": "admin-client", "allow": ["admin"] }
]}

E2) Allow access to clients based on client regex pattern for some roles
Users with role domain-role can access the clients app-domain-a, app-domain-b and app-domain-c.

{"p":[
    { "app": "app-domain-(a|b|c)", "allow": ["domain-role"] }
]}

E3) Allow access to clients based on client regex pattern for some client roles
Users with an access client-role for the respective client can access the client apps denoted by app-domain-a, app-domain-b and app-domain-c.

The $1 in the required role name refers to the matched cliendId in the first regex group.

{"p":[
    { "app": "(app-domain-(a|b|c))", "allow": ["$1.access"] }
]}

E4) Allow access to clients based on client regex pattern for some roles
Users with role domain-role can access the clients app-domain-a, app-domain-b and app-domain-c.

{"p":[
    { "app": "app-domain-(a|b|c)", "allow": ["domain-role"] }
]}

E5) Deny access to the account app for all
{"p":[
    { "app": "account", "allow": ["NONE"] }
]}


The example with some explainations code can be found here.

I think it would be quite useful if had something like this in Keycloak by default.
What do you guys think?


Cheers,
Thomas

Stian Thorgersen

unread,
Apr 16, 2020, 11:32:03 AM4/16/20
to Thomas Darimont, Keycloak Dev
I'd say this just reproduced the capabilities of authorization services, and the correct way for Keycloak to provide a feature to limit what applications a user could login to is by leveraging the authorization services.

I see that you tried that and it didn't work, but that's because there's no integration between authorization services and authenticating to an application.

--
You received this message because you are subscribed to the Google Groups "Keycloak Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to keycloak-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/4f97a561-937d-48c6-844f-4fc9772a3657%40googlegroups.com.

Marek Posolda

unread,
Apr 17, 2020, 4:00:13 AM4/17/20
to st...@redhat.com, Thomas Darimont, Keycloak Dev
In other words, we can have an Authenticator implementation, which will delegate to Authorization services and reject authentication if user is not authorized to authenticate. Is it correct? This will makes sense IMO.

BTV. Authorization services can be integrated to reject authentication if you use "Policy Enforcer" on the application side. However this means that Keycloak server successfully authenticate user (and issue tokens etc) and it is the application, which will reject it on it's side. Which I guess is not exactly the use-case you want to achieve?

Marek

Manfred Duchrow

unread,
Apr 17, 2020, 4:35:32 AM4/17/20
to Keycloak Dev
One of my customers had a similar, but much simpler use case. They wanted authentication being rejected if the user does not have at least one role of the requested client.
I solved this with a RequiredAction plugin that's doing this check at the end of the authentication flow.

On the other hand I don't like it very much to mingle authorization into authentication flow and rejecting an already successful authentication due to authorization restrictions.

EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2)

unread,
Apr 17, 2020, 4:40:54 AM4/17/20
to Marek Posolda, st...@redhat.com, Thomas Darimont, Keycloak Dev

Hi,

 

One opinion from my side: I had the same issue and tried my best to apply the authorization policy idea of https://stackoverflow.com/questions/54305880/how-can-i-restrict-client-access-to-only-one-group-of-users-in-keycloak.

This didn’t work at all. But it sounds quite natural to model it that way.

So I would like to “vote” for Stians proposal to apply Authorization Service handling to login flow, too.

 

Only in case of performance degradations by this change, the authentication flow solution (which sounds like a great workaround, but unfortunately has no applicable license for us, e.g. Apache 2) would be better for us, as this can be activated for each applicable client.

 

Mit freundlichen Grüßen / Best regards

Frank Thiele


Open Source Services 2 - Product Group Customer Success Services (INST-CSS/BSV-OS2)
Bosch.IO GmbH | Ziegelei 7 | 88090 Immenstaad | GERMANY | www.bosch.io
Tel.
+49 30 726112-0 | Telefax +49 30 726112-100 | external.F...@bosch.io

Sitz: Berlin, Registergericht: Amtsgericht Charlottenburg; HRB 148411 B
Aufsichtsratsvorsitzender: Dr.-Ing. Thorsten Lücke; Geschäftsführung: Dr. Stefan Ferber, Dr. Aleksandar Mitrovic, Yvonne Reckling

Stian Thorgersen

unread,
Apr 17, 2020, 6:00:23 AM4/17/20
to Marek Posolda, Thomas Darimont, Keycloak Dev
I think it should not be implemented as an authenticator, but rather a "this user has access to this app" thing. There's a few places this would be useful in the long run:

* Prevent allowing a user to authenticate to an app they shouldn't have access to - although this really can be argued back/forth as permissions should really be checked by the app itself (obviously can be delegated to authz services as an external PDP), and not as part of the auth flow process. In some cases it could be useful though.
* List applications a user is permitted to use for discovery purposes - this can be used in a realm landing page, as well as in the account console. Could also be used for an option within applications themselves to allow linking to other company-wide applications (kinda idea that Google has in most Google apps)
* In admin console as a simple way to see what users can access what apps

Stian Thorgersen

unread,
Apr 17, 2020, 6:02:14 AM4/17/20
to Manfred Duchrow, Keycloak Dev
On Fri, 17 Apr 2020 at 10:35, Manfred Duchrow <manfred...@caprica.biz> wrote:
One of my customers had a similar, but much simpler use case. They wanted authentication being rejected if the user does not have at least one role of the requested client.
I solved this with a RequiredAction plugin that's doing this check at the end of the authentication flow.

That works - but is a bit of a work around right, would probably be nice to have something built-in for this. See my other reply.
 

On the other hand I don't like it very much to mingle authorization into authentication flow and rejecting an already successful authentication due to authorization restrictions.

I agree with you on that one. It's really up to the app to decide if the user is permitted to access it or not, but I can see some situations where it can be useful. Also, there's other uses for "what app can this user access" than simply preventing the auth flow request.
 

--
You received this message because you are subscribed to the Google Groups "Keycloak Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to keycloak-dev...@googlegroups.com.

Stian Thorgersen

unread,
Apr 17, 2020, 6:03:29 AM4/17/20
to EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Thomas Darimont, Keycloak Dev
On Fri, 17 Apr 2020 at 10:41, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2) <external.F...@bosch.io> wrote:

Hi,

 

One opinion from my side: I had the same issue and tried my best to apply the authorization policy idea of https://stackoverflow.com/questions/54305880/how-can-i-restrict-client-access-to-only-one-group-of-users-in-keycloak.


Cool thing about delegating this to authz services in Keycloak is that you can use roles, attributes, groups, or whatever, to decide who should be able to access what app. So it's a lot more flexible than any other option.

Thomas Darimont

unread,
Apr 17, 2020, 7:33:58 AM4/17/20
to Stian Thorgersen, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
I thought about using the authz services as well, but gave up on that idea, since they are IMHO pretty hard to configure at the moment. 
I think a textual declarative configuration would be much easier to work with.
Especially when thinking about configuration as code. 

I'll give the authz services another try...

Btw. @Frank you mentioned that the apache 2 license is not suitable for your environment. Which license would be better in your case?

Cheers, 
Thomas 

Stian Thorgersen

unread,
Apr 17, 2020, 9:33:40 AM4/17/20
to Thomas Darimont, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
On Fri, 17 Apr 2020 at 13:34, 'Thomas Darimont' via Keycloak Dev <keyclo...@googlegroups.com> wrote:
I thought about using the authz services as well, but gave up on that idea, since they are IMHO pretty hard to configure at the moment. 

Solution to that isn't to bring a competing thing to Keycloak though, but rather to find simpler/better ways to configure the auth services ;)
 

Marek Posolda

unread,
Apr 17, 2020, 10:45:46 AM4/17/20
to st...@redhat.com, Thomas Darimont, Keycloak Dev
I am not sure whether it is better authenticator/action or another "1st-class" feature in the Keycloak itself. 1st-class feature means some additional checks all around the codebase and it can't be easily overriden like authentication/action.

On the other hand, authenticator/action won't help with welcome screen, account console etc. Still if we delegate to authorization services, it can become quite complex regarding performance. Especially for deployments with thousands of clients etc. It will be nice to carefully design it if we delegate to authorization services, so it is not so complex like EG. fine-grained admin permissions.

Marek

Thomas Darimont

unread,
Apr 17, 2020, 4:11:42 PM4/17/20
to Marek Posolda, Stian Thorgersen, Keycloak Dev
Hello at all,

Thanks for the interesting discussion so far!

@Stian
I hear you... and I'd love to improve Keycloak in this regard, but I often need to come up with a solution that works now with what is already there.
As I said, I try the same approach with an authenticator, which just uses the internal authorization services with something like a client access policy.
Furthermore I still think that the Authorization Services are quite complicated and the (REST) API for programmatic policy definitions is quite cumbersome.
A textual approach would IMHO be much easier to work with IMHO.

Regarding authorization decisions, I think that they should be decided at the earliest possible moment, in order to avoid unnecessary round-trips.
So, if Keycloak could already decide whether a user can access a particular application during login or token request for a particular client, then this would be a great way 
to avoid unnecessary session creation, reduce round-trips and request latency.

@Marek
Do you have an idea how I could express the following with authorization service policies?
- only users with the role1 or role2 can access a list of clients
- users with role3 should not be able to access a list of clients

With that one could write an authenticator, which evaluates the appropriate policies for a given client. The relevant policies could then be matched by following a naming convention 
for client-ids like common prefixes etc. Depending on the outcome of the policy decision one could either allow or deny the authentication.

@Frank
I just added an Apache 2 License to the extension playground examples.

@All 
Btw. it would be really handy, if Keycloak would support a label mechanism which would allow to assign labels to clients. This could serve as a logical grouping mechanism, which could then be used
to bind all kinds of logic (authentication flows, policies, mappers, etc.) to set of labels without being hard-wired to a particular client / scope. Another option would be to allow Client-Groups, but I think having a label mechanism would be more powerful.

Cheers,
Thomas

Thomas Darimont

unread,
Apr 17, 2020, 7:18:48 PM4/17/20
to Marek Posolda, Stian Thorgersen, Keycloak Dev
Hello,

I gave the Authz based Authenticator idea another spin and I just finished a working prototype: https://github.com/thomasdarimont/keycloak-extension-playground/tree/master/auth-check-authz-policy-extension
The policy evaluation is currently hand-rolled since I couldn't find a better way to evaluate the policies in the current context.

@Marek Do you have any suggestions how I could use the standard AuthorizationProvider#getPolicyEvaluator() in this context?

@Stian would something along this lines suite you better?

Cheers,
Thomas

Stian Thorgersen

unread,
Apr 20, 2020, 3:28:58 AM4/20/20
to Thomas Darimont, Marek Posolda, Keycloak Dev
On Fri, 17 Apr 2020 at 22:11, Thomas Darimont <thomas....@googlemail.com> wrote:
Hello at all,

Thanks for the interesting discussion so far!

@Stian
I hear you... and I'd love to improve Keycloak in this regard, but I often need to come up with a solution that works now with what is already there.
As I said, I try the same approach with an authenticator, which just uses the internal authorization services with something like a client access policy.
Furthermore I still think that the Authorization Services are quite complicated and the (REST) API for programmatic policy definitions is quite cumbersome.
A textual approach would IMHO be much easier to work with IMHO.

Appreciate that - works just fine as an extension, but when baking it into Keycloak itself we need to make sure it's more manageable. As such two separate "authz approaches" would be too much effort to maintain.

Not sure, but perhaps a basic DSL could be useful for authz services in general. Don't think the export of authz services settings for a client is particularly nice to read.
 

Regarding authorization decisions, I think that they should be decided at the earliest possible moment, in order to avoid unnecessary round-trips.
So, if Keycloak could already decide whether a user can access a particular application during login or token request for a particular client, then this would be a great way 
to avoid unnecessary session creation, reduce round-trips and request latency.

@Marek
Do you have an idea how I could express the following with authorization service policies?
- only users with the role1 or role2 can access a list of clients
- users with role3 should not be able to access a list of clients

With that one could write an authenticator, which evaluates the appropriate policies for a given client. The relevant policies could then be matched by following a naming convention 
for client-ids like common prefixes etc. Depending on the outcome of the policy decision one could either allow or deny the authentication.

@Frank
I just added an Apache 2 License to the extension playground examples.

@All 
Btw. it would be really handy, if Keycloak would support a label mechanism which would allow to assign labels to clients. This could serve as a logical grouping mechanism, which could then be used
to bind all kinds of logic (authentication flows, policies, mappers, etc.) to set of labels without being hard-wired to a particular client / scope. Another option would be to allow Client-Groups, but I think having a label mechanism would be more powerful.

Discussed this with Pedro a long time ago, that it would be nice to have some sort of "grouping" mechanism for resources, and we came to exactly that conclusion that some labels/tags would be nice. 

Marek Posolda

unread,
Apr 20, 2020, 3:29:01 AM4/20/20
to Thomas Darimont, Stian Thorgersen, Keycloak Dev, Pedro Igor Silva
Hi Thomas,

On 18. 04. 20 1:18, Thomas Darimont wrote:
Hello,

I gave the Authz based Authenticator idea another spin and I just finished a working prototype: https://github.com/thomasdarimont/keycloak-extension-playground/tree/master/auth-check-authz-policy-extension
The policy evaluation is currently hand-rolled since I couldn't find a better way to evaluate the policies in the current context.
Thanks, I will try to take a look.


@Marek Do you have any suggestions how I could use the standard AuthorizationProvider#getPolicyEvaluator() in this context?

I am not sure. TBH I am not that familiar with the details of authorization services at the implementation level. So my best advice would be to look at the javadoc, existing codebase which using that and existing tests. CCing Pedro, who is best expert regarding authorization services.

More below


@Stian would something along this lines suite you better?

Cheers,
Thomas

On Fri, 17 Apr 2020 at 22:11, Thomas Darimont <thomas....@googlemail.com> wrote:
Hello at all,

Thanks for the interesting discussion so far!

@Stian
I hear you... and I'd love to improve Keycloak in this regard, but I often need to come up with a solution that works now with what is already there.
As I said, I try the same approach with an authenticator, which just uses the internal authorization services with something like a client access policy.
Furthermore I still think that the Authorization Services are quite complicated and the (REST) API for programmatic policy definitions is quite cumbersome.
A textual approach would IMHO be much easier to work with IMHO.

Regarding authorization decisions, I think that they should be decided at the earliest possible moment, in order to avoid unnecessary round-trips.
So, if Keycloak could already decide whether a user can access a particular application during login or token request for a particular client, then this would be a great way 
to avoid unnecessary session creation, reduce round-trips and request latency.

@Marek
Do you have an idea how I could express the following with authorization service policies?
- only users with the role1 or role2 can access a list of clients
- users with role3 should not be able to access a list of clients

I think both the use-cases can be modelled with the policies. AFAIK Role-Policy can have both "positive" and "negative" logic, so the logic like "user with role3 should not be able to access a list of clients" should be doable with the negative logic. Also you can add more roles into the single role-policy.

Also I guess that every client, which is subject to authorization, can have it's own "Resource" or eventually also "Authorization Scope", but maybe authorization scope is not needed. Then you may need to create "Permission" as a binding between resources (clients) and policies. Maybe there is better way, but I would probably start with a model like this and then see if it's fine or not...

Marek

Stian Thorgersen

unread,
Apr 21, 2020, 4:42:28 AM4/21/20
to Thomas Darimont, Marek Posolda, Keycloak Dev
I was thinking more along the lines of a on/off option on clients that enabled/disables leveraging authz services for this type of access. When it is enabled a special resource is created with authz services for the client with some scope "access" or something like that.

As a post-authentication check we would check if user has access to the client if this is enabled. This also allows querying authz services for client "resources" a given user has access to.

Stian Thorgersen

unread,
Apr 23, 2020, 8:32:45 AM4/23/20
to Thomas Darimont, Marek Posolda, Keycloak Dev
One low-hanging fruit way would also be to have some required role option on a client. That would not need to use authorization services.

What I imagine is that a client can have an access option where one can select [all], [client-role], [realm-role] or [authorization services]. [client-role] would let you select a single role from that client, [realm-role] would let you select a single realm role. [authorization] would setup a [resource] with an [access] scope for the client, then you can configure policies as you wish. Initially the [client-role] and [realm-role] can be just an attribute on the client, but in the future it may be a shortcut for configuring [authorization services].

The flow would then be:

1. Authenticate user through auth flow
2. Check if the authenticated user can access app
3. Run required actions

As a note we want to change required actions to more generic actions. Where they should have a priority order. When that is done step 2 can be done as an action perhaps rather than as a separate thing.

We would also need some way of listing what applications a specific user can access, something like "List<Client> findClientsUserCanAccess(UserModel user)". That can then be used within account console for the user to discover applications, in the admin console for an admin to get a quick overview over what applications a user can access, and finally within some REST API that would allow clients to list other applications the user can access in order to provide shortcuts/switchers between applications.

Pedro Igor Craveiro e Silva

unread,
Apr 23, 2020, 1:23:49 PM4/23/20
to st...@redhat.com, Thomas Darimont, Marek Posolda, Keycloak Dev
Sorry for kicking in so late. I really missed this one ...

There is an extension you can check from our site https://www.keycloak.org/extensions.html. See "Client Authorization".

As said here, I also think that adding a different policy engine/language is not really a good idea. Besides, we have discussed in the past the idea of resource-less permissions where evaluation is simple based on some policy language (which one, not yet there).

Thomas, I don't know the issues you had when using authorization services. Some of them, you have described and I'm happy to discuss them in more detail so we can improve whatever you think can be improved.

Back to the original issue.

I do think that the best way to address this is by using authorization services. There you have a quite rich and extensible policy engine that you don't need to care about when enforcing access during authentication. That extension seems like a good start.

Moreover, we also need to improve how we would expose the configuration to users and not make something as complicated as fine-grained admin permission.

Pedro Igor Craveiro e Silva

unread,
Apr 23, 2020, 1:33:54 PM4/23/20
to Thomas Darimont, Marek Posolda, Stian Thorgersen, Keycloak Dev
On Fri, Apr 17, 2020 at 8:18 PM 'Thomas Darimont' via Keycloak Dev <keyclo...@googlegroups.com> wrote:
Hello,

I gave the Authz based Authenticator idea another spin and I just finished a working prototype: https://github.com/thomasdarimont/keycloak-extension-playground/tree/master/auth-check-authz-policy-extension
The policy evaluation is currently hand-rolled since I couldn't find a better way to evaluate the policies in the current context.

@Marek Do you have any suggestions how I could use the standard AuthorizationProvider#getPolicyEvaluator() in this context?

Not surprisingly, you are missing some important bits here and there. Only a few people know this part of the code and I'm happy to discuss it with you.

org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator is the main entry point to the policy evaluation engine. It is really dependent on the resources/scopes you are protecting which are also managed by Keycloak.

Regarding your question, it is possible to just evaluate policies too. I mean, given a set of one or more policies, iterate over them and check their result. Remember that policies are not associated with resources so they can be reused in different scenarios to build different permissions for different resources/scopes.

The code to evaluate only policies (which is part of that DefaultPolicyEvaluator) is quite simple. Here is an example:

           PolicyProvider policyProvider = authorizationProvider.getProvider(parentPolicy.getType());

            if (policyProvider == null) {
                throw new RuntimeException("Unknown parentPolicy provider for type [" + parentPolicy.getType() + "].");
            }

            policyProvider.evaluate(new DefaultEvaluation(permission, executionContext, parentPolicy, decision, authorizationProvider, decisionCache));

Basically, you get the provider for a given policy and run "evaluate" by passing some context so that the policy can do its work. The context is basically the current user, any attribute you want to make available to your policies, realm, client, etc, etc.

So yeah, it should be quite simple to do this. And again, leveraging all the flexibility we have in terms of access control methods and the possibility to add more like a Keycloak specific DSL for policies.
 

Pedro Igor Craveiro e Silva

unread,
Apr 23, 2020, 1:42:17 PM4/23/20
to Thomas Darimont, Marek Posolda, Stian Thorgersen, Keycloak Dev
On Fri, Apr 17, 2020 at 5:11 PM 'Thomas Darimont' via Keycloak Dev <keyclo...@googlegroups.com> wrote:
Hello at all,

Thanks for the interesting discussion so far!

@Stian
I hear you... and I'd love to improve Keycloak in this regard, but I often need to come up with a solution that works now with what is already there.
As I said, I try the same approach with an authenticator, which just uses the internal authorization services with something like a client access policy.
Furthermore I still think that the Authorization Services are quite complicated and the (REST) API for programmatic policy definitions is quite cumbersome.
A textual approach would IMHO be much easier to work with IMHO.

Sorry, but I don't agree. Is that complicated?

        ClientResource client = getClient();
        AuthorizationResource authorization = client.authorization();
        RolePolicyRepresentation representation = new RolePolicyRepresentation();

        representation.setName("Realm Client Role Policy");
        representation.addRole("Client Role A");

        authorization.policies().role().create(representation);

Now, if you are talking about the more "generic" API version. Which we have to support cases where you have custom policy providers then I agree. 

Like I said somewhere else, a DSL is something we want to add. Mainly due to the fact that you won't be forced to manage resources at Keycloak.

In fact, we could right away support JS as our DSL. But there are issues with JS engine that I hope with GraalVM and Truffle, we could be able to support policies written in different languages.
 

Pedro Igor Craveiro e Silva

unread,
Apr 23, 2020, 1:51:51 PM4/23/20
to Thomas Darimont, Stian Thorgersen, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
On Fri, Apr 17, 2020 at 8:33 AM 'Thomas Darimont' via Keycloak Dev <keyclo...@googlegroups.com> wrote:
I thought about using the authz services as well, but gave up on that idea, since they are IMHO pretty hard to configure at the moment. 
I think a textual declarative configuration would be much easier to work with.
Especially when thinking about configuration as code. 

Declarative policies are good but not a silver bullet. There are some other options out there that have their own language for expressing policies.

First of all, it is one more thing you need to learn. And a good DSL goes beyond what you are proposing here. Then you have to perform really well when evaluating this, like considering partial evaluation, etc. In fact, performance is one of the main points we should improve right now. Although we had improved a lot, mainly when evaluating permissions for a set of one or few resources. Evaluate permissions for every single resource or evaluating all policies you have defined is costly. There are quite a few options we need to explore that might help like adding some parallelism to evaluation (restrictions due to running in a J2E container), etc.

Another thing you should worry about is how do you pass data to these declarative policies so that they can do their thing. Currently, policies run inside Keycloak and they have access to everything we want. Very close to them. By using a declarative approach we should be able to also pass all this contextual data so that we can have richer policies. And not only a static set of options.
 

Thomas Darimont

unread,
Apr 27, 2020, 11:46:28 AM4/27/20
to Pedro Igor Craveiro e Silva, Stian Thorgersen, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
Hello Pedro et al.,

wow - thank you all for the great discussion so far!

@Stian

> One low-hanging fruit way would also be to have some required role option on a client.
This idea sounds promising and would solve my example use-case, but my gut feeling tells me, that this might be too short-sighted in the long run.
I think a grouping mechanism for clients, where you could then add this required role option would be better than configuring this on individual clients.

I like the access-option idea. However one should make sure that this also works with more complex access-polices.

@Pedro
The "LocalAuthorizationService" in the featured "Client Authorization" extension https://www.keycloak.org/extensions.html looks interesting
https://github.com/cloudtrust/keycloak-authorization/blob/master/src/main/java/io/cloudtrust/keycloak/protocol/LocalAuthorizationService.java#L75

However, it also patches a few Keycloak classes like OIDCLoginProtocol, which makes it difficult to be used in newer Keycloak versions.
https://github.com/cloudtrust/keycloak-authorization/blob/91ecebe876a4ace82a2078c6471ab65d588e3bbe/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java#L238

I try to incorporate your suggestions with the PolicyProvider#evaluate API another spin here:
https://github.com/thomasdarimont/keycloak-extension-playground/blob/master/auth-check-authz-policy-extension/src/main/java/com/github/thomasdarimont/keycloak/auth/authzpolicy/AuthzPolicyAuthenticator.java#L64
, although I didn't have much success last time.


Regarding the code:
```

PolicyProvider policyProvider = authorizationProvider.getProvider(parentPolicy.getType());

if (policyProvider == null) {
    throw new RuntimeException("Unknown parentPolicy provider for type [" + parentPolicy.getType() + "].");
}

policyProvider.evaluate(new DefaultEvaluation(permission, executionContext, parentPolicy, decision, authorizationProvider, decisionCache));
```

If I have a policy "special-client-access" that should limit access to a group of clients (expressed as a nested "client policy") to users that have certain roles (expressed as a "role policy").
The "client policy" just contains client1,client2 and client3.
The "role policy" just contains role1

If all policies of the "special-client-access" apply in the given context, I want to allow access to the client.

How could I express that with the above API?

The executionContext probably needs the current user and the current target client, but what is a decision, what is my "parentPolicy" ("special-client-access"?), and why do I need need a decisionCache here?
when I wrote the example, I played a while with the API but eventually gave up, but as said I give it another try :)

@all
I didn't want to invent a new mechanism just for the fun of it :) I just wanted to find a way that works now which allows me to implement the use-case mentioned above.

The current authorization services framework is quite powerful and a very flexible authorization toolkit, which I'd love to use it but, when I try I fail most of the time.
Many things are either not documented, are lacking examples, or are intended to be used outside of Keycloak via the Authorization Service REST API.

When I give the above authenticator another spin, I try to jot down some more concrete things that I'm currently missing or that are difficult to use.


> Sorry, but I don't agree. Is that complicated?
I have the impression that I stepped on your toe, if this is the case then I apologize... sorry, that was not my intention! :)

```

        ClientResource client = getClient();
        AuthorizationResource authorization = client.authorization();
        RolePolicyRepresentation representation = new RolePolicyRepresentation();

        representation.setName("Realm Client Role Policy");
        representation.addRole("Client Role A");

        authorization.policies().role().create(representation);
```
No this particular example is not difficult per se, but requires applications to replicate a part of their domain model as resources to Keycloak,
but for this I need to start another discussion on another day :)

Back to the discussion about a DSL:

I choose to use a textual representation for access-policies because I wanted a single and easily diffable format that I put into source control, that can easily be transferred between environments.
The complex object model is currently quite difficult to port between environments if possible at all?!

With a textual DSL which is just interpreted I don't need to create, update, sync object models, which makes it easy to transfer them across different environments.
Other authorization frameworks like casbin https://github.com/casbin/casbin#policy-persistence (Java Library: https://github.com/casbin/jcasbin) follow a similar approach.

Perhaps we could think of a textual representation of an authorization policy set that can be imported into Keycloak.

> Declarative policies are good but not a silver bullet. There are some other options out there that have their language for expressing policies.
I agree with you here. As always it's a trade-off, a powerful DSL can be quite complex and hard to understand, on the other hand, an easy DSL can is probably quite inflexible, but easy to understand and does the job.


> First of all, it is one more thing you need to learn. And a good DSL goes beyond what you are proposing here.
My intent was not to invent a new general DSL :) I wanted to build something small and deliberately inflexible which solves a very specific problem.

Wrt. to the performance part, yes that's something where authorization services need some improvements, but this is also material for another discussion.


> Another thing you should worry about is how do you pass data to these declarative policies so that they can do their thing.
> Currently, policies run inside Keycloak and they have access to everything we want. Very close to them. By using a declarative approach
> we should be able to also pass all this contextual data so that we can have richer policies. And not only a static set of options.
Yes, one can take the declarative approach quite far :) Need to think about it more.


Thanks again for the valuable discussions! Again (too) much food for thought!

Cheers & stay safe!
Thomas

Pedro Igor Craveiro e Silva

unread,
Apr 27, 2020, 1:48:08 PM4/27/20
to Thomas Darimont, Stian Thorgersen, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
As a general note: That is the beauty of open-source :)

On Mon, Apr 27, 2020 at 12:46 PM Thomas Darimont <thomas....@googlemail.com> wrote:
Hello Pedro et al.,

wow - thank you all for the great discussion so far!

@Stian
> One low-hanging fruit way would also be to have some required role option on a client.
This idea sounds promising and would solve my example use-case, but my gut feeling tells me, that this might be too short-sighted in the long run.
I think a grouping mechanism for clients, where you could then add this required role option would be better than configuring this on individual clients.

I like the access-option idea. However one should make sure that this also works with more complex access-polices.

@Pedro
The "LocalAuthorizationService" in the featured "Client Authorization" extension https://www.keycloak.org/extensions.html looks interesting
https://github.com/cloudtrust/keycloak-authorization/blob/master/src/main/java/io/cloudtrust/keycloak/protocol/LocalAuthorizationService.java#L75

However, it also patches a few Keycloak classes like OIDCLoginProtocol, which makes it difficult to be used in newer Keycloak versions.
https://github.com/cloudtrust/keycloak-authorization/blob/91ecebe876a4ace82a2078c6471ab65d588e3bbe/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java#L238
 
Yes, it does. But we would need anyway to change some other bits to enforce access when authenticating users, right?



I try to incorporate your suggestions with the PolicyProvider#evaluate API another spin here:
https://github.com/thomasdarimont/keycloak-extension-playground/blob/master/auth-check-authz-policy-extension/src/main/java/com/github/thomasdarimont/keycloak/auth/authzpolicy/AuthzPolicyAuthenticator.java#L64
, although I didn't have much success last time.


Regarding the code:
```
PolicyProvider policyProvider = authorizationProvider.getProvider(parentPolicy.getType());

if (policyProvider == null) {
    throw new RuntimeException("Unknown parentPolicy provider for type [" + parentPolicy.getType() + "].");
}

policyProvider.evaluate(new DefaultEvaluation(permission, executionContext, parentPolicy, decision, authorizationProvider, decisionCache));
```

If I have a policy "special-client-access" that should limit access to a group of clients (expressed as a nested "client policy") to users that have certain roles (expressed as a "role policy").
The "client policy" just contains client1,client2 and client3.
The "role policy" just contains role1

If all policies of the "special-client-access" apply in the given context, I want to allow access to the client.

How could I express that with the above API? 

The executionContext probably needs the current user and the current target client, but what is a decision, what is my "parentPolicy" ("special-client-access"?), and why do I need need a decisionCache here?
when I wrote the example, I played a while with the API but eventually gave up, but as said I give it another try :)

The first thing to do is decide how you would match a client or a set of clients to policies. For instance, that extension does it by having a specific resource in the client authorization settings. Once you do that, is just a matter of running the evaluator.

But we can do it differently:

* We can have a UI for creating Realm-level Policies. Then have a select box at the client UI to choose an "Authentication Policy" from any of these "realm-level" policies (similar to how fine-grained admin works)
* We can have an authentication execution and configure there a list of policies that must be satisfied when the user is authenticated. Clients could then override the default flow.

I mean, there are different options here to do what you want. API usage is not really the main point but how we would allow users to configure the behavior. The example I gave you is only to show how policy is evaluated behind the scenes. But most of the time you should do what that extension is doing. See https://github.com/cloudtrust/keycloak-authorization/blob/91ecebe876a4ace82a2078c6471ab65d588e3bbe/src/main/java/io/cloudtrust/keycloak/protocol/LocalAuthorizationService.java#L75.
 

@all
I didn't want to invent a new mechanism just for the fun of it :) I just wanted to find a way that works now which allows me to implement the use-case mentioned above.

That extension does not work for you? Couldn't we just try something on top of it and improve UX, for instance?
 

The current authorization services framework is quite powerful and a very flexible authorization toolkit, which I'd love to use it but, when I try I fail most of the time.

That is OK. I don't blame you :) In fact, I think we should have this kind of feedback to know what can be improved or change completely. Feel free to open another thread where we can discuss each of these attempts and why they failed.
 
Many things are either not documented, are lacking examples, or are intended to be used outside of Keycloak via the Authorization Service REST API.

I must agree with you. For advanced usage, we lack more docs. Although we have some bits in our documentation. I also tried to cover the most important bits through some quickstarts. Some of them are also using Spring Boot.
 

When I give the above authenticator another spin, I try to jot down some more concrete things that I'm currently missing or that are difficult to use.

> Sorry, but I don't agree. Is that complicated?
I have the impression that I stepped on your toe, if this is the case then I apologize... sorry, that was not my intention! :)

Nah ...
 

```
        ClientResource client = getClient();
        AuthorizationResource authorization = client.authorization();
        RolePolicyRepresentation representation = new RolePolicyRepresentation();

        representation.setName("Realm Client Role Policy");
        representation.addRole("Client Role A");

        authorization.policies().role().create(representation);
```
No this particular example is not difficult per se, but requires applications to replicate a part of their domain model as resources to Keycloak,
but for this I need to start another discussion on another day :)

That is exactly what I meant by the resource-less approach.
 

Back to the discussion about a DSL:

I choose to use a textual representation for access-policies because I wanted a single and easily diffable format that I put into source control, that can easily be transferred between environments.
The complex object model is currently quite difficult to port between environments if possible at all?!

Not sure. Depending on your application you can just have something like what we have in our quickstarts. You can, but you are not forced to have a 1:1 mapping between all resources in Keycloak and those you are actually protecting at your application. Resources can represent a set of one or more protected resources. Policies should be reusable too. If you have a JSON with some common policies, shared between different environments/clients, you should be able to just import then.

If we really want to be portable, not only across environments but also across vendors, we should consider XACML. It also deserves a separate discussion ...


With a textual DSL which is just interpreted I don't need to create, update, sync object models, which makes it easy to transfer them across different environments.
Other authorization frameworks like casbin https://github.com/casbin/casbin#policy-persistence (Java Library: https://github.com/casbin/jcasbin) follow a similar approach.

I agree. That is why I mentioned the resource-less permissions.

See. I don't disagree with you about using a DSL. We need that. I just don't think we should introduce something like this without considering authorization as a whole.

In addition to that, I think a token-based approach to centralized authorization is much more powerful than just obtain decisions from a PDP.
 

Perhaps we could think of a textual representation of an authorization policy set that can be imported into Keycloak. 

> Declarative policies are good but not a silver bullet. There are some other options out there that have their language for expressing policies.
I agree with you here. As always it's a trade-off, a powerful DSL can be quite complex and hard to understand, on the other hand, an easy DSL can is probably quite inflexible, but easy to understand and does the job.

Exactly. And that is what we were doing with JS. And how I would like to make this DSL available so that people can just use something they know. As I mentioned, Truffle can help here in the future and we could support policies written in any well-known language ...
 

> First of all, it is one more thing you need to learn. And a good DSL goes beyond what you are proposing here.
My intent was not to invent a new general DSL :) I wanted to build something small and deliberately inflexible which solves a very specific problem.

That is fine. But this is not so small and IMO we do need to consider other use cases. I'm sure people will like this and try to leverage it in other parts of the server for different purposes.
 

Wrt. to the performance part, yes that's something where authorization services need some improvements, but this is also material for another discussion.

Yeah .. Mainly when fetching permissions from every single resource from the server. And the cache is not warmed up.

Stian Thorgersen

unread,
Apr 28, 2020, 3:29:24 AM4/28/20
to Thomas Darimont, Pedro Igor Craveiro e Silva, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
On Mon, 27 Apr 2020 at 17:46, Thomas Darimont <thomas....@googlemail.com> wrote:
Hello Pedro et al.,

wow - thank you all for the great discussion so far!

@Stian
> One low-hanging fruit way would also be to have some required role option on a client.
This idea sounds promising and would solve my example use-case, but my gut feeling tells me, that this might be too short-sighted in the long run.
I think a grouping mechanism for clients, where you could then add this required role option would be better than configuring this on individual clients.

I like the access-option idea. However one should make sure that this also works with more complex access-polices.

Direct role mapping can and should be done on a single client for sure. However, I see your point with regards to authz services that you'd want to apply a policy to a group of clients, and not to individual clients.

Pedro Igor Craveiro e Silva

unread,
Apr 28, 2020, 8:30:09 AM4/28/20
to st...@redhat.com, Thomas Darimont, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
IMO, the use cases being discussed can be addressed like that:

* Add Realm-Level Policies. Policies that can be used across different clients and functionalities in Keycloak.
* Add an "Authentication Policy" in Clients so that you can choose which realm-level policies should be evaluated when authenticating users for a specific a client
* Potentially support to associate policies directly to the authentication flows/executions. For the use case we are discussing, it should be possible to create a new policy provider that holds a list of clients and the policies that should be evaluated.

This grouping mechanism also reminds me of another discussion we recently had about labels.

Pedro Igor Craveiro e Silva

unread,
Apr 28, 2020, 8:32:35 AM4/28/20
to st...@redhat.com, Thomas Darimont, EXTERNAL Thiele Frank (TNG, INST-CSS/BSV-OS2), Marek Posolda, Keycloak Dev
And by leveraging the policy model we have, we can support different types of access control mechanisms. Not only RBAC.
Reply all
Reply to author
Forward
0 new messages