Keycloak - 将所有用户映射到角色

Keycloak - Get all Users mapped to roles

我知道 keycloak 暴露在下面 api,

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-services</artifactId>
    <version>2.0.0.Final</version>
</dependency>

具有完整的文档here。我在这里找不到所需的 api 来获取所有映射到特定角色的用户。

问题陈述 - 我需要从 keycloak 服务器中选择所有具有特定角色的用户。我需要向所有角色映射到他们的用户发送电子邮件。

有一个未完成的 feature request 通过 API 请求此功能。

同时,如果您的需求是一次性的,您可以通过查询连接 KEYCLOAK_ROLE 到 USER_ROLE_MAPPING 到 USER_ENTITY[= 的数据库来获取用户名(或电子邮件地址) 12=]

类似于:

SELECT username
FROM keycloak_role kr 
   JOIN user_role_mapping rm ON kr.id = rm.role_id
   JOIN user_entity ue ON rm.user_id = ue.id
WHERE kr.name = 'your_role_name';

根据 documentation 看来是这样 API:

GET /{realm}/clients/{id}/roles/{role-name}/users

它在那里有一段时间了。然而,在这个旧版本中,不可能通过这种方式获得超过 100 个用户。稍后修复并添加了分页选项。

这是另一个有趣的查询,它还会显示其他有用的字段。

SELECT kr_role.REALM_ID 'Realm', cl.CLIENT_ID 'Realm Client', 
    kr_role.NAME 'Role Name', 
    kr_role.DESCRIPTION 'Role Description', 
    user_ent.USERNAME 'Domain ID', user_ent.EMAIL 'Email'
  FROM keycloak_role kr_role, user_role_mapping role_map, 
    user_entity user_ent, client cl
  WHERE role_map.USER_ID = user_ent.ID
  AND kr_role.ID = role_map.ROLE_ID
  AND kr_role.CLIENT = cl.ID
  AND cl.REALM_ID = '<realm_name>'
  AND cl.CLIENT_ID = '<client_name>'
  ORDER BY 1, 2, 3;

更新后的休息端点现在应该可以做到这一点。

Set<UserRepresentation> usersOfRole = realmResource.roles().get(roleName).getRoleUserMembers();
SELECT username,
       kr.NAME,
       kr.REALM_ID
FROM KEYCLOAK_ROLE kr
JOIN USER_ROLE_MAPPING rm ON kr.id = rm.role_id
JOIN USER_ENTITY ue ON rm.user_id = ue.id
ORDER BY USERNAME,
         NAME,
         REALM_ID;

如果有人仍在搜索 Postgres 查询以在 keycloak 数据库中查找有关 users/roles/groups 的信息,我最近想到了这个。

它使用两个 CTE 来明确组和角色(对于组中的组递归,因为它们可以嵌套在任意深度,并使用它们的父级获取复合角色)和一个简单的 UNION 用于组和直接分配。

请注意 WHERE 子句,您可以在其中限制领域和不同方面。您可以搜索

  • 来自特定用户的所有角色(仅匹配 username
  • 分配了特定角色的所有用户(匹配 role_name
  • 来自特定组的所有内容(我有时在投影中没有 username 列的情况下使用它只是为了查看组具有什么角色。请注意组列中的前缀)
-- flat out GROUPS in GROUPS
WITH RECURSIVE groups AS (
    SELECT
        g.id,
        g.id AS parent_group,
        g.name,
        g.name AS parent_name,
        g.realm_id,
        1 AS iter
    FROM
        keycloak_group g
    UNION
    SELECT
        groups.id,
        parents.parent_group,
        groups.name,
        parents.name,
        groups.realm_id,
        groups.iter + 1
    FROM
        groups
        INNER JOIN keycloak_group parents ON groups.parent_group = parents.id
),
-- Collect roles and composite roles
roles AS (
    SELECT
        r.id,
        r.name AS role_name,
        null AS base_role,
        c.client_id
    FROM
        keycloak_role r
        LEFT JOIN client c ON r.client = c.id
    UNION
    SELECT
        r.id,
        r2.name,
        r.name,
        c.client_id
    FROM
        keycloak_role r
        JOIN composite_role cr ON r.id = cr.composite
        JOIN keycloak_role r2 ON r2.id = cr.child_role
        LEFT JOIN client c ON r.client = c.id
)
SELECT DISTINCT
    username,
    role_name,
    base_role,  -- for composite roles
    client_id,
    source,
    realm_name
FROM
    (
        -- Roles from Groups
        SELECT
            ue.username,
            roles.role_name,
            roles.base_role,
            roles.client_id,
            ue.realm_id,
            'group ' || g.name AS source,
            realm.name AS realm_name
        FROM
            user_entity ue
            JOIN realm ON ue.realm_id = realm.id
            JOIN user_group_membership ugm ON ue.id = ugm.user_id
            JOIN groups g ON g.id = ugm.group_id
            JOIN group_role_mapping grm ON g.parent_group = grm.group_id
            JOIN roles roles ON roles.id = grm.role_id
        UNION
        -- direct role assignments on User
        SELECT
            ue.username,
            roles.role_name,
            roles.base_role,
            roles.client_id,
            ue.realm_id,
            'direct',
           realm.name
        FROM
            user_entity ue
            JOIN realm ON ue.realm_id = realm.id
            JOIN user_role_mapping urm ON ue.id = urm.user_id
            JOIN roles roles ON roles.id = urm.role_id
    ) AS a
WHERE
    realm_name = 'realm_name'
    AND (
        -- username = 'username'
        role_name IN ('roleName')
        -- source = 'group GROUPNAME'
    )
ORDER BY
    username,
    role_name
;

此查询适用于 keycloak 9 到 16.1.1(我从 docker hub 获得的最后一个 jboss/keycloak 版本)。