我尝试通过使用信任客户端并为公共客户端颁发令牌来通过模拟颁发访问令牌。我已经设置了令牌交换权限,请求可以正常工作。然而,我的问题是在AZP中发出的令牌似乎包含错误的客户端。
以下是我的请求:
curl -v -X POST \
-d "client_id=impersonator-client" \
-d "client_secret=<secret omitted>" \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "audience=target-client" \
--data-urlencode "requested_subject=john.doe" \
http://localhost:8080/auth/realms/swarm/protocol/openid-connect/token基本上,我希望通过使用“john.doe-client”模拟用户来获得用户“impersonator”的访问令牌。签发的令牌应该是为"target-client“铸造的,但是,AZP仍然包含"impersonator-client”。
我这样做的原因是,应该可以使用外部身份验证工作流登录,这最终提供了一个访问令牌,然后可以在我的后端服务器上进行验证,该服务器使用受信任的客户端进行模拟。
根据文档(https://www.keycloak.org/docs/latest/securing_apps/#_token-exchange),受众应该定义应该为其铸造令牌的目标客户端。
关于权限:
我用一个引用"impersonator- client“的客户端策略设置了"admin-impersonating.permission.users”权限。"target- client“本身配置了一个权限"token-exchange.permission.client.e236d39c-9b9c-4815-b734-90364fea4e91”,其中包含一个引用"impersonator-client“的客户端策略。我是不是漏掉了什么?这里的问题是文档似乎是错的。文档使用"user-impersonated.permission.users“而不是"admin-impersonating.permission.users”。当我尝试这样做时,请求甚至被拒绝了。
这是Keycloak中的一个bug,还是我做错了什么?
提前感谢!
发布于 2021-11-30 08:39:07
好吧,我遇到了这个问题,最大的问题之一是它阻止了我的应用程序( target-client)执行刷新令牌工作流。如果我使用预期的refresh_token -client执行启动授权,如果我使用starting-client (它与标记中的azp字段匹配),我会得到一个错误消息Session doesn't have the required grant.,我会得到Invalid refresh token. Token client and authorized client don't match。
我找到了这个issue,它将我引向this,它在请求令牌交换时指定starting-client的client_id是导致访问和刷新令牌的错误azp并将一切搞得一团糟的原因。我不知道这是不是故意的,文档是错的,还是这是一个bug,我将来会遇到问题。将来我会关注这些bug报告,了解更多细节。
下面是进行令牌交换(我使用的是Keycloak 15.0.2)并从中进行刷新的工作方法。这是Kotlin但你明白我的意思了。这里假设您已经执行了必要的配置here。
// tokenManager makes sure I have a valid access token from "starting-client"
// via client_credentials grant. You can swap with however you want to get this token.
val adminToken = keycloak.tokenManager().accessTokenString
// exchange your admin token for starting-client for a user token at target-client
val response = Unirest.post("${keycloakProperties.authServerUrl}/realms/${keycloakProperties.realm}/protocol/openid-connect/token")
.field("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange") // using the keycloak custom token-exchange grant
.field("client_id", "target-client") // set to the target client ID, not the starting as the docs say!
.field("subject_token", adminToken) // seems the exchange grant reads the starting-client from the subject token, so setting "client_id" to "starting-client" (which is what I had been doing) forces the exchanged token into an invalid state
.field("requested_token_type", "urn:ietf:params:oauth:token-type:refresh_token") // refresh_token will issue you both an access and refresh token
.field("audience", "target-client")
.field("requested_subject", userId) // the keycloak user ID we are requesting a token for
.asObject(AccessTokenResponse::class.java) // this is just some DTO so I can deserialize the JSON into an object for easy use, I happened to have this from the Keycloak admin client laying around
.body
// we have our access token now. let's refresh it for the sake of the example, but normally your app would do this periodically on the client end.
val refreshedToken = Unirest.post("${keycloakProperties.authServerUrl}/realms/${keycloakProperties.realm}/protocol/openid-connect/token")
.field("grant_type", "refresh_token")
.field("client_id", "target-client")
.field("refresh_token", accessToken.refreshToken)
.asObject(AccessTokenResponse::class.java)
.body
// voila, refreshedToken has given you a new access and refresh token
log.debug("New access token {}, refresh token {}", refreshedToken.accessToken, refreshedToken.refreshToken)https://stackoverflow.com/questions/62466630
复制相似问题