Hello Dmitry,
After some trial and error, we were able to achieve having only pertinent groups in the
token, although not as elegant as your script. So now we have it configured the way we
want... approximately... Do you care to elaborate a little bit more on the possibilities
to mitigate that security issue you mentioned in the email. The idea behind allowing a
user to login if required group membership constraint is fulfilled, is quite important to
us, which means that we need to find a different way from what we are doing right now. And
of course, disabling SSO for all the clients is not a solution :)
Looking forward to hearing from you soon!
Thanks in advance,
Ronald
-----Original Message-----
From: Dmitry Telegin <dt(a)acutus.pro>
Sent: 10.Nov.2018 12:34 AM
To: Ronald Demneri <ronald.demneri(a)amdtia.com>; keycloak-user(a)lists.jboss.org
Subject: Re: [keycloak-user] filter group claim in token per client
Ronald,
Here are some Pro Tips(tm) for you :)
- use keycloakSession.context.client.clientId to retrieve client ID (works for both tokens
and userinfo);
- use Java.from() and Java.to() to convert objects and arrays from Java to JavaScript and
vice versa;
- use more JavaScript-fu like map() and filter() to avoid looping over arrays;
- use RegExp for generic case-insensitive pattern matching.
With the above, your whole mapper could look as simple as this:
==========================================
/**
* Available variables:
* user - the current user
* realm - the current realm
* token - the current token
* userSession - the current userSession
* keycloakSession - the current userSession */
var client = keycloakSession.context.client.clientId;
var groups = Java.from(user.groups)
.map(function(group) {
return group.name;
})
.filter(function(name) {
return RegExp("(\\w+)-" + client + "-(\\w+)",
"i").test(name);
})
token.setOtherClaims("fGroup", Java.to(groups, "java.lang.String[]"))
==========================================
Please also read my earlier reply about the potential security issue with the script
authenticator and how to mitigate it.
In fact, this problem (restricting access to clients based on group membership) has
surfaced here at least three times during last month, so I think I'd write an article
with the solution walkthrough. Stay tuned and good luck :)
Dmitry Telegin
CTO, Acutus s.r.o.
Keycloak Consulting and Training
Pod lipami street 339/52, 130 00 Prague 3, Czech Republic
+42 (022) 888-30-71
E-mail: info(a)acutus.pro
On Tue, 2018-11-06 at 20:51 +0000, Ronald Demneri wrote:
I configured the client to not use the userinfo endpoint for the
group mapping. Instead I used the id token, and everything looks good now (no errors in
the log, and the client gets the claim, and assigns permissions accordingly) . Anyhow,
the question remains, is there a way to get the client id using the script mapper?
Thanks in advance,
Ronald
Sent from my HTC
----- Reply message -----
> From: "Ronald Demneri" <ronald.demneri(a)amdtia.com>
> > To: "Ronald Demneri" <ronald.demneri(a)amdtia.com>, "Dmitry
Telegin"
> > <dt(a)acutus.pro>, "keycloak-user(a)lists.jboss.org"
> > <keycloak-user(a)lists.jboss.org>
Subject: [keycloak-user] filter group claim in token per client
Date: Tue, Nov 6, 2018 16:08
Hello again,
Upon testing login and experimenting where the claim should be inserted, I found out that
the duplicate print() is a result of including the claim in both ID access tokens. The
error comes as a result of including the claim in the userinfo token, and probably that is
why the userinfo endpoint does not contain the claim when the client application requests
it.
Any idea how to solve it?
Thanks in advance,
Ronald
-----Original Message-----
From: Ronald Demneri
Sent: 06.Nov.2018 12:01 PM
> To: Ronald Demneri <ronald.demneri(a)amdtia.com>; Dmitry Telegin
> <dt(a)acutus.pro>; keycloak-user(a)lists.jboss.org
Subject: RE: [keycloak-user] filter group claim in token per client
So, I am looking at the logs and receive the following when going to App1 > Client
Scopes > Evaluate:
2018-11-06 10:51:42,407 INFO [stdout] (default task-1892)
############################################ APP1
2018-11-06 10:51:42,407 INFO [stdout] (default task-1892)
############################################
2018-11-06 10:51:42,407 INFO [stdout] (default task-1892) We are here!!!
2018-11-06 10:51:42,408 INFO [stdout] (default task-1892)
############################################
But when trying to actually log in to the client, I receive the following:
2018-11-06 10:52:20,465 INFO [stdout] (default task-1891)
############################################ APP1
2018-11-06 10:52:20,465 INFO [stdout] (default task-1891)
############################################
2018-11-06 10:52:20,465 INFO [stdout] (default task-1891) We are here!!!
2018-11-06 10:52:20,466 INFO [stdout] (default task-1891)
############################################
2018-11-06 10:52:20,474 INFO [stdout] (default task-1891)
############################################ APP1
2018-11-06 10:52:20,474 INFO [stdout] (default task-1891)
############################################
2018-11-06 10:52:20,474 INFO [stdout] (default task-1891) We are here!!!
2018-11-06 10:52:20,475 INFO [stdout] (default task-1891)
############################################
2018-11-06 10:52:20,691 ERROR
[org.keycloak.protocol.oidc.mappers.ScriptBasedOIDCProtocolMapper]
(default task-1891) Error during execution of ProtocolMapper script:
org.keycloak.scripting.ScriptExecutionException: Could not execute
script 'token-mapper-script_filteredGroupsMapper' problem was:
TypeError: null has no such function "toUpperCase" in <eval> at line
number 31
Line 31 is as follows:
31: var client = token.getIssuedFor().toUpperCase();
32: print("############################################ " +
client);
So why does it display an error, when in fact it also displays the correct form of the
clientId in upper case? And why is the log entry duplicated? ATM, I removed the client
scope mapper and have recreated the script mapper only for this client.
Regards,
Ronald
-----Original Message-----
From: Ronald Demneri
Sent: 06.Nov.2018 11:05 AM
> > To: 'Ronald Demneri' <ronald.demneri(a)amdtia.com>; 'Dmitry
Telegin'
> > <dt(a)acutus.pro>; 'keycloak-user(a)lists.jboss.org'
> > <keycloak-user(a)lists.jboss.org>
Subject: RE: [keycloak-user] filter group claim in token per client
Hello Dmitry,
A colleague of mine helped solving the issue with the array, and I can see the filtered
groups in the Access token. I also used token.getIssuedFor() to get the client name and
make the evaluation of the filtered groups dynamic. The problem now is that this new claim
is not present in the userinfo. This is the script that we came up with (configured both
as client scopes (possibly define as a default client scope) as well as script mapper
specific to this client for test purposes - claim names are different of course):
> [kcadmin@keycloak bin]$ ./kcadm.sh get client-scopes [ {
"id" : "4ea94866-044e-4590-a2da-f25c980f08b4",
"name" : "Filtered_Groups",
"protocol" : "openid-connect",
"attributes" : {
"display.on.consent.screen" : "true"
},
"protocolMappers" : [ {
"id" : "7d3c521a-b291-4f43-ad87-6891ed9584d3",
"name" : "Filtered Groups",
"protocol" : "openid-connect",
"protocolMapper" : "oidc-script-based-protocol-mapper",
"consentRequired" : false,
"config" : {
"multivalued" : "true",
"userinfo.token.claim" : "true",
"id.token.claim" : "true",
"access.token.claim" : "true",
"claim.name" : "fGroup",
"jsonType.label" : "String",
"script" : "/**
* Available variables:
* user - the current user
* realm - the current realm
* token - the current token
* userSession - the current userSession
* keycloakSession - the current userSession
*/
//insert your code here...
//So, first we need to know, how many names should be added to
the new claim,
var username = user ? user.username : \"anonymous\";
var groups = user.getGroups();
var group_array = groups.toArray();
//print(\"########################################## \" +
username);
var client = token.getIssuedFor();
//print(\"############################################ \" +
client);
var clUp = client.toUpperCase();
//print(clUp);
var group_APP = \"APP-\" + clUp + \"-USERS\";
var group_ROL = \"ROL_SSO-\" + clUp + \"-ADMIN\";
var group_filtered = [];
for (var i in group_array) {
var gn = group_array[i].getName();
var gnUp = gn.toUpperCase();
if (gnUp === group_APP || gnUp === group_ROL) {
group_filtered.push(\"/\" + gn);
}
}
//Then we declare the new array.
var l = group_filtered.length;
var group_token =
java.lang.reflect.Array.newInstance(java.lang.String.class, l);
for (var f in group_filtered) {
group_token[f] = group_filtered[f];
//print(group_token[f]);
}
//And submit the array as token
token.setOtherClaims(\"fGroup\", group_token);"
}
} ]
}
This is the userinfo data for my account:
{
"sub": "bad7ff26-2a70-446f-a635-06fdbe1bec55",
"Group": [
"/APP-App1-Users/TGR-Team-ABC",
"/APP-App1-Users/TGR-Team-DEF",
"/APP-App1-Users",
"/APP-MySmallApp-Users"
],
"email_verified": false,
"name": "Ronald Demneri",
"preferred_username": "u151302",
"given_name": "Ronald",
"family_name": "Demneri"
The group claim is inserted by the group mapper created for this client, and the idea is
to remove it once the script mapper works as expected.
What do you think is going on? Is this behavior normal?
Thanks in advance,
Ronald
-----Original Message-----
From: Ronald Demneri
Sent: 05.Nov.2018 12:12 PM
> To: 'Ronald Demneri' <ronald.demneri(a)amdtia.com>; Dmitry Telegin
> <dt(a)acutus.pro>; keycloak-user(a)lists.jboss.org
Subject: RE: [keycloak-user] filter group claim in token per client
Hello,
In the script authenticator there was authenticationSession which I used to get the
clientId. There is no such variable in the script mapper, and If I define such mapper in
the client template, I suppose I'd need some mechanism to get the client name and then
make the filtering of the groups that need to be inserted in the token. How do I do that?
Is there any documentation available for this online?
Thanks again for your support!
Ronald
-----Original Message-----
> From: keycloak-user-bounces(a)lists.jboss.org
> <keycloak-user-bounces(a)lists.jboss.org> On Behalf Of Ronald Demneri
Sent: 05.Nov.2018 11:00 AM
> To: Dmitry Telegin <dt(a)acutus.pro>; keycloak-user(a)lists.jboss.org
Subject: Re: [keycloak-user] filter group claim in token per client
Hello Dmitry,
Thanks for the response. In fact I tried that before posting here, created a custom
script mapper for the client that I have configured. The problem is that the script will
return a list of objects, not an array of strings, which is what I am expecting.
What do I need to pay extra attention in order to solve this?
Thanks in advance and Regards,
Ronald
-----Original Message-----
> From: Dmitry Telegin <dt(a)acutus.pro>
Sent: 05.Nov.2018 6:54 AM
> To: Ronald Demneri <ronald.demneri(a)amdtia.com>;
> keycloak-user(a)lists.jboss.org
Subject: Re: [keycloak-user] filter group claim in token per client
Hello Ronald,
As in the case with authentication, JavaScript is to the rescue again :) You can create a
script mapper for groups that will do additional group filtering based on the client, and
use it instead of the built-in one.
To avoid explicitly configuring it for each and every client, you can create a Client
Scope (can be called "Client Template" depending on the KC version), define the
mapper in the scope, and add it do default scopes.
Cheers,
Dmitry Telegin
CTO, Acutus s.r.o.
Keycloak Consulting and Training
Pod lipami street 339/52, 130 00 Prague 3, Czech Republic
+42 (022) 888-30-71
> E-mail: info(a)acutus.pro
On Fri, 2018-11-02 at 10:30 +0000, Ronald Demneri wrote:
> Hello everyone,
>
> Is there a way to filter the groups a user is a member of per client, based on
clientId (which is part of the group name(s) in AD). Let's say that user Ronald is
member of group_client1, group_client2 and group_client3, so using a group mapper, the
token will contain a claim like group:["group_client1",
"group_client2", "group_client3"]. Upon logging in to client1 app, I
want to customize the group claim so that it contains only the respective group_client1
value.
>
> Thanks in advance,
>
> Ronald
> _______________________________________________
> keycloak-user mailing list
> keycloak-user(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/keycloak-user
_______________________________________________
keycloak-user mailing list
keycloak-user(a)lists.jboss.org
https://lists.jboss.org/mailman/listinfo/keycloak-user