PAC4J在 RP发起的登出过程中不提供id_token_hint
运行位于 https://github.com/pac4j/play-pac4j-scala-demo/ 的PAC4J Play演示应用时,我发现 集中登出 功能在与(较新版本的)Keycloak搭配使用时不起作用,Keycloak要求在RP发起的登出场景中必须携带 id_token_hint 参数。
调试代码流程时,我理解在将 OidcProfile 对象保存到会话存储时,身份令牌信息会丢失。
特别是由于提交 https://github.com/pac4j/pac4j/commit/a32dfca7012f924ef3eb23f920a3e8d298393c0a:
// pac4j-oidc/src/main/java/org/pac4j/oidc/profile/OidcProfile.java
@Override
public void removeLoginData() {
removeAttribute(OidcProfileDefinition.ID_TOKEN);
removeAttribute(OidcProfileDefinition.ACCESS_TOKEN);
removeAttribute(OidcProfileDefinition.REFRESH_TOKEN);
}
有哪些推荐的解决方案?
我是不是应该扩展 OidcProfile 类并实现一个不会清除身份令牌的自定义实现?
不过从安全方面看会有什么后果?把身份令牌/访问令牌/刷新令牌保存在会话存储中(即作为cookie)究竟有什么问题?毕竟cookie是用服务器端只有服务器知道的密钥来进行加密的。
解决方案
确实,当你使用 PlayCookieSessionStore 时,你的用户资料会被保存到Play的 cookie中。
这本身并没有安全问题。问题在于cookie的大小有限,这也是在保存到 OidcProfile 之前会移除较大信息的原因。否则,cookie无法写入,用户资料也就无法保存。
但你说得对,这对于集中登出来说是一个问题,需要发送参数 id_token_hint。
一个解决方案是使用另一种存储,例如 PlayCacheSessionStore 或 PlayEhCacheSessionStore。
另一种解决方案是更新 PlayCookieSessionStore,添加一个标志来指示是否调用 clearUserProfiles 方法,但它要么移除所有令牌,要么不移除。我不确定在不移除任何令牌的情况下是否真的可行。
或者你的提议是正确的:覆盖 profileDefinition 来创建一个不移除id_token的自定义 OidcProfile。