问题描述
我有一个受Keycloak 11.0.2保护的spring boot应用程序,我的Keycloak设置如下:
- 名为
Central
的领域,角色为CentralWebUser
,客户为SpringWeb
。客户有-
Access Type
:public
且仅启用一个流,即Standard Flow Enabled
-
Valid Redirect URIs
:http:// localhost:8000 / *
-
- 名为
SpringApp
且角色为WebUser
和客户端spring_brokering
的2ª领域
第二个领域是第一个领域的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
和它的机密。
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
及其密码。登录成功,但是我得到拒绝访问,这意味着用户springuser
没有角色WebUser
。但是,该角色是在第二个领域(即 SpringApp
)内分配给该用户的。
有趣的是,如果我在第一个领域中创建一个身份提供者Mapper External Role to Role
(在IDP SpringAppIDP
配置中),将WebUser
的外部角色映射到CentralWebUser
并将弹簧属性更改为:
keycloak.security-constraints[0].authRoles[0]=CentralWebUser
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/services/*
我能够登录,这意味着Keycloak知道用户具有WebUser
角色,因此将该角色映射到CentralWebUser
角色。
我想知道是否可以将角色从外部IDP显式导入到内部IDP中吗?或者,是否可以(以及如何)代表用户向令牌中的Central
和SpringWeb
领域中拥有该用户角色的用户请求令牌,而不必显式创建角色每个用户角色的映射器。
解决方法
我想知道是否可以显式导入角色 从外部 IDP 变成内部 IDP?或者如果(以及如何)我可以 代表将拥有该用户的用户请求令牌 该令牌中来自 Central 和 SpringWeb Realm 的角色, 无需为每个用户显式创建角色映射器 角色。
没有为每个用户角色明确创建角色映射器,我发现的唯一解决方案是扩展 Keycloak 代码;这有明显的缺点。
回想起来,实际上是有道理的,Keycloak 没有提供一种从外部 IDP 自动导入所有角色的开箱即用方式。例如,如果我使用 Google 作为外部 IDP,为什么我的内部 IDP(i.e.,Keycloak)应该关心 Google 使用的角色的确切名称?!。最有可能的是,这些角色对于内部 IDP 来说毫无意义,当它们有意义时,它们可能有不同的名称。无论如何,对于这些例外情况,您可以使用角色映射器功能。
尽管如此,为了使过程自动化,我创建了一个文件,将内部 IDP的角色映射到外部 IDP,例如:
ROLE A | ROLE B
....
我还有一个带有角色映射器示例的 模板 的 JSON 文件,其中包含一些稍后要替换的标签(, 字段 role
和 { {1}})。
通过脚本,我读取具有角色之间映射关系的文件,并使用 Keycloak Admin REST API 创建角色、映射器等。
我使用的逻辑如下:
- 如果该角色在外部 IDP 中不存在,我只是跳过并假设这是一个错误;
- 如果内部 IDP 中不存在该角色,我会将其创建为 Realm 角色;为此,我使用端点
external.role
- 最后,我使用端点
POST /{realm}/roles
和POST /{realm}/identity-provider/instances/{alias}/mappers
模板角色映射器文件的内容(相应地替换了其标签)创建了角色映射器。
不在 external IDP 中创建 Realm 角色的理由是 external IDP 中的所有角色应该已经从 LDAP 加载。对于内部 IDP,我确实创建了,因为可以预期,对于映射 1 到 1,来自 LDAP(加载到 外部 IDP)的角色尚未在其上创建内部 IDP。