
























在Keycloak 14.0.0版本中,即使启用了-Dkeycloak.profile.feature.token_exchange=enabled预览功能,客户端配置页面中确实不会直接显示"exchange token"选项。这是因为旧版令牌交换(V1)需要额外的细粒度权限配置。
-Dkeycloak.profile.feature.admin_fine_grained_authz=enabled
-Dkeycloak.profile.feature.token_exchange=enabled
重启Keycloak服务使配置生效。




1 用户在keycloak平台登录
curl -X POST 'https://kc.com/auth/realms/demoo/protocol/openid-connect/token' -H 'Accept: application/json' --data-urlencode 'grant_type=password' --data-urlencode 'username=test' --data-urlencode 'password=123456' --data-urlencode 'client_id=wso2' --data-urlencode 'client_secret=abf99c64-db24-43fb-b63b-c60213b8052f' --data-urlencode 'scope=openid'
2 用户在wso2平台通过urn:ietf:params:oauth:grant-type:jwt-bearer方式生成对应的token
curl -X POST 'https://wso2.com/oauth2/token' -H 'Content-Type: application/json' -H 'Content-Type: application/json' -u '3N5OKJnQozVc8pPKWHSf1CTLgwQa:HEj3QGF3bPxLIJbTpEmanW5mIjEa' --basic -d '{
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": "kc-access-token",
"scope": "openid apim:subscribe"
}'
3 用户在keycloak平台根据wso2的token来校验成keycloak的token,注意wso2中的客户端生成的token类型可以是jwt类型和default类型,但scope中必须包含openid的,否则无法获取oauth2/userinfo接口。
curl -X POST 'https://kc.com/auth/realms/fabao/protocol/openid-connect/token' -H 'Content-Type: application/x-www-form-urlencoded' -u 'wso2:abf99c64-db24-43fb-b63b-c60213b8052f' --basic --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' --data-urlencode 'subject_token=wso2-jwt-token' --data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:access_token' --data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:access_token' --data-urlencode 'scope=openid' --data-urlencode 'subject_issuer=wso2'
idn_oauth2_access_token_scope表添加openid的scope,它就可以调用/oauth2/userinfo接口了,有几秒缓存。
为sp应用添加openid的scope,在acp的deployment.toml中,添加相关配置,以开启openid的功能
[oauth]
allowed_scopes = ["openid", "default", "am_application_scope"]
[oauth.grant_type.client_credentials]
enable_openid_scope = true
解决上面白屏的方法:原因是在非客户端认证时,allowed_scopes = ["openid", "default", "am_application_scope"] 也添加了openid的scope,这个对于没有用户信息的请求来说,它在生成id_token时会出现错误,包含还有相关权限的问题,导致了白屏;解决方法是我们重写一下
org.wso2.carbon.apimgt.impl.issuers.SystemScopesIssuer类,然后对方法getAuthorizedScopes()进行了重构,对于client_credentials认证并且authenticatedUser不为空时,手动添加了openid这个scope,保证了这个token可以访问/oauth2/userinfo端点。
重启服务后,进行sp的客户端认证,返回值会有openid和default,并有id_token的内容
{
"access_token": "3baba7f7-3437-345e-89e3-ee9ea9ae6c05",
"scope": "default openid",
"id_token": "eyJ4NXQiOiJNekF6TVRGak9EUTFNRE5qT1RVMVpEQTROR1E1TURrell6RTNNV0k0TW1SbFpHVTNZelpqWWprNFpHUmtNMlJoTW1Jd01qQXhZekpsTUdKak5qZG1OdyIsImtpZCI6Ik16QXpNVEZqT0RRMU1ETmpPVFUxWkRBNE5HUTVNRGt6WXpFM01XSTRNbVJsWkdVM1l6WmpZams0WkdSa00yUmhNbUl3TWpBeFl6SmxNR0pqTmpkbU53X1JTMjU2IiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiWEIwUWxaWTZ0TVZTWC05U2VrYmpyUSIsImF1ZCI6InNIaXN4ajIzc0JxN2ZZMDcwd2hWTzdwd1VCd2EiLCJzdWIiOiJiMzk4MjcyYi0zYTZjLTQ0MGYtOTQ5NS04OGMzYzE3NThhMzkiLCJuYmYiOjE3NzcyODA0MzksImF6cCI6InNIaXN4ajIzc0JxN2ZZMDcwd2hWTzdwd1VCd2EiLCJhbXIiOlsiY2xpZW50X2NyZWRlbnRpYWxzIl0sImlzcyI6Imh0dHBzOi8vdGVzdC1hcGltLnBrdWxhdy5jb20vb2F1dGgyL3Rva2VuIiwiZXhwIjoxNzgwODgwNDM5LCJpYXQiOjE3NzcyODA0MzksImp0aSI6IjdiYzYyY2U1LTFjODktNDliOS1iNGVmLTY2YmY5NzUxMTEzZSJ9.fPlMbjUvSw9Y59RHe-cIW1MA0DHTnOJ_0-S5Bxoc6yqF6VBa8xZAyjjFtaKxXULMqpcH0f-qKsxoT9X7LnEwGgUWhBHVKmuxK0WHDwsHIyEo1yscVc-Ap6HpfRf_cu8nX0taW0wPdeAdUCgPVGUas2d8YDnz5bKVSlydk9xVxwqvvyJvA_GcpOJ2W14Zk34bjlqOWN6jcaXkUfwrAZbheZudnKVWdI_hYOq0bd94pkRF7-af0b_h7rk4BuAatu_Z8qPhClvWZLpg1hMFRWwobOvBbuijmjMPkcsy0-JSLhc-i5_YXQ7q-U_uuDi1AiEijVlfHb7Uij5zQ98S_jF1Mw",
"token_type": "Bearer",
"expires_in": 3600000
}
在客户端的Permissions页面中,找到token-exchange权限,点击进入配置:
创建策略:
Create Policy按钮wso2-token-exchange-policy配置策略:
绑定策略:
token-exchange权限页面由于WSO2 APIM是外部令牌颁发者,需要在Keycloak中将其配置为受信任的Identity Provider:
wso2-apim(自定义名称)WSO2 APIMhttps://test-apim.pkulaw.com/oauth2/authorizehttps://test-apim.pkulaw.com/oauth2/tokenhttps://test-apim.pkulaw.com(WSO2 APIM的颁发者URL)在WSO2 APIM的客户端配置中,确保:
配置完成后,使用以下请求格式交换令牌:
curl -X POST 'https://your-keycloak-host/auth/realms/{realm}/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Authorization: Basic {base64 kc_client_id:kc_client_secret)}' \
-d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
subject_token={WSO2_APIM_TOKEN}&
subject_token_type=urn:ietf:params:oauth:token-type:access_token&
requested_token_type=urn:ietf:params:oauth:token-type:access_token&
subject_issuer=wso2&
scope=openid profile email'
"Client not allowed to exchange":
"Invalid subject token":
subject_issuer参数与令牌中的iss一致"Subject token issuer not trusted":
** “User already exists”**:
oauth2/userinfo如果配置后仍遇到问题,建议提供具体的错误信息以便进一步排查。
当keycloak中的本地用户,它的用户名与wso2的token中sub(类型于uuid)同名时,你的wso2交换token将无法完成,因为在交换token时,它会将wso2中sub作为用户名写到keycloak本地用户表,当写时有重复时,会出现错误,如下
{
"error": "invalid_token",
"error_description": "User already exists"
}
由于交换token是后端完成的,所以是无交互的动作,这时你在idp中定义的first login flow是没有执行的,如果找一个方法解决让它执行,我们就可以把它和kc本地用户做映射了,问题也就解决了。
问题原因
外部 token exchange(TokenEndpoint.importUserFromExternalIdentity / exchangeExternalToken)在 getUserByFederatedIdentity 查不到 (IdP, sub) 时,会按 email 或 username 去建用户;若本地已有同名用户,就直接抛 invalid_token + "User already exists"。
浏览器里的 first broker login 则会让用户确认后把 IdP 绑到已有账号,而 token exchange 没有这条路径,所以会出现你描述的行为。
实现说明
在 TokenEndpoint.java 中做了这些事:
这样:当 IdP 的 sub 在 Keycloak 里还没有对应联邦记录,但 计算出的 username(或 email)与本地用户冲突 时,会 复用该本地用户并建立关联,而不再报 "User already exists"。
子类如需定制策略,可 override autolinkLocalUserForExternalTokenExchange。
-Dkeycloak.profile.feature.token_exchange=enabled
-Dkeycloak.profile.feature.admin_fine_grained_authz=enabled
Client not allowed to exchange
user info call failure
{
"error": "invalid_client",
"error_description": "Audience not found"
}
{
"error": "invalid_client",
"error_description": "Invalid client credentials"
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。