如何从外部 IDP 读取/导入角色到 Keycloak
Posted
技术标签:
【中文标题】如何从外部 IDP 读取/导入角色到 Keycloak【英文标题】:How to read/import the roles from an external IDP into Keycloak 【发布时间】:2021-02-14 10:38:03 【问题描述】:我有一个使用 Keycloak 11.0.2 保护的 Spring Boot 应用程序,我的 Keycloak 设置如下:
一个名为Central
的领域,角色为CentralWebUser
,客户端为SpringWeb
。客户有
Access Type
: public
并且只启用了一个流,即Standard Flow Enabled
Valid Redirect URIs
: http://localhost:8000/*
一个名为 SpringApp
的 2ª 领域,角色 WebUser
和客户端 spring_brokering
一个名为springuser
的用户具有领域角色WebUser
客户端spring_brokering
只有Standard Flow Enabled
设置为ON,Valid Redirect URIs
:http://localhost:8080/*,和Access Type
:Confidential
第二个领域是第一个领域的 IDP。因此,要登录用户转到Central
登录页面并选择IDP SpringAppIDP
。
IDP配置如下:
alias
: SpringAppIDP
,除了启用的选项外,其他所有内容均为 OFF
授权 URL、令牌 URL 等设置为来自 SpringApp
端点的 URL(e.g.,
Authorization URL
: http://127.0.0.1:8080/auth/realms/SpringApp/protocol/openid-connect/auth)
客户端 ID 和客户端密码分别是 spring_brokering
及其密码。
在 Spring 方面,我有以下属性值得一提:
server.port = 8000
keycloak.realm = Central
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = SpringWeb
keycloak.public-client=true
keycloak.security-constraints[0].authRoles[0]=WebUser
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/services/*
当我访问 http://127.0.0.1:8080/services
时,我被重定向到 Keycloak Central
领域登录页面,然后我单击 SpringAppIDP
并输入用户名 springuser
及其密码。登录成功,但是我得到了一个access denied,这意味着用户springuser
没有WebUser
的角色。但是,该角色是在第二个领域内分配给该用户的(即SpringApp
)。
有趣的是,如果在第一个 Realm 中创建身份提供者 Mapper External Role to Role
(在 IDP SpringAppIDP
配置中)将 WebUser
的外部角色映射到 CentralWebUser
并将 spring 属性更改为:
keycloak.security-constraints[0].authRoles[0]=CentralWebUser
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/services/*
我能够登录,这意味着 Keycloak 知道用户拥有WebUser
角色,因此将该角色映射到CentralWebUser
角色。
我想知道是否可以将角色从外部 IDP 显式导入到内部?或者,如果(以及如何)我可以代表用户请求一个令牌,该令牌将拥有来自该令牌中 Central
和 SpringWeb
领域的用户角色,而无需为每个用户显式创建角色映射器角色。
【问题讨论】:
【参考方案1】:我想知道是否可以显式导入角色 从外部 IDP 变成内部 IDP?或者如果(以及如何)我可以 代表将拥有该用户的用户请求令牌 该令牌中来自 Central 和 SpringWeb Realm 的角色, 无需为每个用户显式创建角色映射器 角色。
没有为每个用户角色显式创建角色映射器,我发现的唯一解决方案是扩展 Keycloak 代码;这有明显的缺点。
回想起来,实际上 Keycloak 不提供开箱即用的自动从外部 IDP 导入所有角色的方法是有道理的。例如,如果我使用 Google 作为外部 IDP,为什么我的内部 IDP(即,Keycloak)应该关心 Google 使用的角色的确切名称?!。最有可能的是,这些角色对于内部 IDP 来说毫无意义,并且当它们有意义时,它们可能具有不同的名称。无论如何,对于这些例外情况,可以使用角色映射器功能。
不过,为了使流程自动化一点,我创建了一个文件,将 internal IDP 的角色映射到 external IDP,例如:
ROLE A | ROLE B
....
我还有一个 JSON 文件,其中包含角色映射器示例的 模板,其中一些标签随后将被替换(例如字段role
和external.role
)。
通过脚本,我读取具有角色之间映射的文件,并使用Keycloak Admin REST API 创建角色、映射器等。
我使用的逻辑如下:
如果 external IDP 中不存在该角色,我只是跳过并假设这是一个错误; 如果internal IDP 中不存在该角色,我将其创建为领域角色;为此,我使用端点POST /realm/roles
最后,我使用端点POST /realm/identity-provider/instances/alias/mappers
和JSON
模板角色映射器文件的内容创建角色映射器(相应地替换了它的标签)。
不在external IDP 中创建领域角色的理由是,来自external IDP 的所有角色都应该已经从LDAP 加载。对于 internal IDP,我确实创建了,因为对于映射 1 到 1,LDAP 中的角色(加载到 external IDP)可能尚未创建内部 IDP。
【讨论】:
以上是关于如何从外部 IDP 读取/导入角色到 Keycloak的主要内容,如果未能解决你的问题,请参考以下文章
Keycloak IdP SAML2 将 XML 元数据导出到 SP