We are using a company based realm successfully with a number of clients with a single realm. Now we start getting more clients where not all users should be allowed to login to and I wonder how we can limit certain clients to specific users (or groups or roles) only.
And a user with role mappings that have no effective roles neither for the realm nor for that client.
So, that user should not be allowed to access that client. However, I can properly authenticate with that user for that client application. Any idea what’s wrong?
Nothing wrong in that . Roles and groups are linked to Authorization .As long as user exist in the realm authentication will be successful however it will not have mapped roles .You have to handle role information in the token to restrict access to specfic features in the code.
Roles do not forbid user to authenticate to a client.
Keycloak only handles authentication requests, returns roles and scopes in access token, then client needs to handle this information. Also, you can enable fine-grained authorization on your client (just a note, I know about this, but not how to make it works).
We have a similar issue, and resolved it with a custom authentication flow adapter.
Confused a bit between authorization and authentication. I guess authentication ensures which user is actually talking to KC and verifying the credentials. This is purely realm based.
Then, authorization is what I’m looking for where I want to limit the access of users to specific clients only.
@claudioweiler could you probably point me in the direction where and how to enable fine-grained authorization which should be based on the client roles? Or can you share some details about your custom adapter?
Fine-grained authorization is very customizable, but I can not help in these.
About authorization flow:
Imagine a service you have that should be protected. A user tries to access it, then service redirects to keycloak that will authenticate user, fill in tokens, and redirects back to service. Now, on expected openid flow, your service should verify user permissions based on tokens returned, and enable/disable functionalities.
In our case, we want that Keycloak just don’t redirect back to service, so we made an adapter that show a message to user that he do not have access do requested resource.
This need is unfortunately not supported by Keycloak.
You have 3 workarounds to meet your need :
create a realm by users groups if you can deduce users group before login and set authorized clients in each realm
use the powerfull Authorization Services but you need to do some (minor) implementations in app code source (it can be difficult if you have many apps …)
add a custom Authenticator in your authentication flow to validate the user access
I spent a week trying to achieve client access limitation based on user group (or role), yet I did not find a clean solution.
As @claudioweiler mentioned by using Roles Keycloak won’t limit the access, the client must handle the access by receiving the role information from Keycloak. Since we have 10+ web services (clients) using completely different technologies implementing client side role checking is not an option for us.
The closest I got for the solution was using @M3lkior suggestion adding a custom Authenticator script for the authentication flow. However the access limitation based on checking user groups/roles by Keycloak can be achieved, but it comes with a big disadvantage: you lose the SSO function.
In order to get the user attributes within your custom Authenticator script you must pass the “Username Password Form” section in the authentication flow otherwise the user object is not being populated and you get null for the user variable. It does not matter if you have the cookie auth type also set, the user variable remains null, it is not being populated by passing the cookie section. This means for every clients you must type your username and password to have Keycloak check your attributes. Unfortunately losing SSO is not an option for us as we have 10+ clients.
I really like using Keycloak, I believe if group/role based access limitation to clients would be natively supported then it would become an even more powerful and commonly used system
I wrote the following Authenticator script for this:
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
function authenticate(context) {
var allowed_groups = ['foo', 'bar'];
var username = user ? user.username : "anonymous";
var groups = user.getGroups();
var group_array = groups.toArray();
for (var i in group_array) {
var gn = group_array[i].getName();
if (allowed_groups.indexOf(gn) >= 0) {
LOG.info("Access granted for user '" + username + "' for being member of LDAP group '" + gn + "'");
return context.success();
}
}
LOG.info("Access denied for user '" + username + ". for not being member of any of the following LDAP groups: " + allowed_groups);
context.failure(AuthenticationFlowError.IDENTITY_PROVIDER_DISABLED, context.form().setError(
"User doesn't have the required LDAP group membership to view this page", null).createForm("error.ftl"));
return;
}
@Yoso89, maybe this is a drawback in script based authenticator adapter.
We use an adapter based on “org.keycloak.authentication.Authenticator” Java implementation.
Just a little extra note, as you mention web services as clients. If user knows URI of the web services, he still can go there, he just can’t authenticate and use authentication flow configured for the client.