feat(sso): Add PKCE support, separate OIDC sub and username#2793
feat(sso): Add PKCE support, separate OIDC sub and username#2793Youwenqwq wants to merge 5 commits into
Conversation
- Consume OIDC state once and bind it to the client, method, and IP. - Encode popup and redirect values and restrict postMessage to the API origin. - Reject expired entries when atomically popping keyed cache values. Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
- Add an optional OIDC subject claim setting with legacy identity fallback. - Read claims from the verified ID token and query UserInfo for missing values. - Verify the UserInfo subject and use the username claim for auto-registration. Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
- Add backward-compatible settings for S256 PKCE and OIDC nonce validation. - Store verifiers and nonces in the one-time login state. - Submit PKCE verifiers during token exchange and reject mismatched ID token nonces. Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
- Remove unused organization, application, and JWT public key entries from active SSO settings. - Drop the corresponding unreferenced configuration constants.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a37f4d33ab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if entry.Expired() { | ||
| return *new(T), false |
There was a problem hiding this comment.
Preserve recursive cache invalidation on expired parents
Changing Pop to return false for expired entries changes the generic remove-and-return semantics used by Cache.deleteDirectoryTree: if a parent directory cache entry has expired but a child directory cache was refreshed later or has a longer custom TTL, invalidating/deleting the parent stops here and leaves the child cache/link entries usable until their own TTL. Keep Pop as a raw remove or add a separate unexpired-pop helper for SSO state so tree invalidation can still walk expired parents.
Useful? React with 👍 / 👎.
Summary / 摘要
为单点登录功能添加了可配置的 subject key,并增加了 PKCE 验证方式和 nonce 以在一定程度上增加安全性。
为什么要修改
在当前版本(v4.2.3, a92d59d)的 OpenList 中,单点登录功能若选择 OIDC 方式,将只有 “OIDC 用户名键” 可设定;在开启 SSO 自动注册后,该用户名键将作为 OpenList 中的 User.SsoID 用于绑定唯一身份。这存在一个问题: 通常用户可在 IdP 侧修改用户名,一旦用户名发生变更,将产生一个新的 SsoID,导致 OpenList 侧重复创建并绑定一个新的用户。
注意到原代码中,选择 Casdoor 作为提供商时,可以通过 subject key 来辨别 IdP 侧唯一用户;事实上大多数 IdP 都会向应用提供一个稳定的身份 ID,因此应作为通用 OIDC 选项进行配置。
另外,当前版本中,前端切换任意 SSO 登录平台似乎都只会显示通用的单点登录配置项,这个 PR 没有改变这个行为。
用户可感知的变化
重要实现变化
由 AI 总结,人工审核
使用已验证的 ID Token 对象读取 claims,不再手动解码 JWT payload。
将用户身份与显示用户名分离:
PKCE verifier 和 nonce 存储在一次性 state 中,并在回调时消费。
state 同时绑定客户端 IP 和回调 method,过期 state 在 Pop 时也会被拒绝。
OIDC V1 回调和其他 SSO 回调共用安全的 HTML/重定向响应逻辑。
配置和兼容性
由 AI 总结,人工审核修改
新增配置:
默认值:
subject_key 留空时继续使用 OIDC Username Key 作为 SSO ID,因此现有部署默认保持原有身份映射。
将其改为 sub 后,已有用户的旧 SsoID 不会自动迁移,首次登录可能被识别为新用户;上线前需要评估现有用户映射。
没有数据库 schema 或唯一索引变更,也没有 SSO API 路由变更。被删除的遗留设置不会再被初始化或读取;数据库中已有
的旧设置记录不会主动删除,但没有运行时作用。
非兼容模式现在要求弹窗 opener 与 OpenList API URL 同源。依赖跨域 opener 的特殊部署需要调整来源配置或使用兼容模式。state 仍是进程内存储,多实例部署的回调路由限制与原实现一致。
/ 此 PR 包含破坏性变更。
/ 此 PR 修改了公开 API、配置、存储格式或迁移行为。
/ 此 PR 需要关联仓库同步修改。
Related repository/ 关联仓库:
Testing / 测试
go test ./...Checklist / 检查清单
/ 我已阅读 CONTRIBUTING。
/ 我确认此贡献符合仓库许可证、贡献规范和行为准则。
gofmt,go fmt, orprettierwhere applicable./ 我已按适用情况使用
gofmt、go fmt或prettier格式化变更代码。/ 我已在适用情况下请求相关维护者或代码所有者审查。
AI Disclosure / AI 使用声明
/ 此 PR 包含 AI 辅助内容。
Tools used / 使用工具:
Usage scope / 使用范围:
Code generation / 代码生成
Refactoring / 重构
Documentation / 文档
Tests / 测试
Translation / 翻译
Review assistance / 审查辅助
I have reviewed and validated all AI-assisted content included in this PR.
/ 我已审核并验证此 PR 中的所有 AI 辅助内容。
I have ensured that all AI-assisted commits include
Co-Authored-Byattribution./ 我已确保所有 AI 辅助提交都包含
Co-Authored-By归属信息。I can reproduce all AI-assisted content included in this PR without any AI tools.
/ 我可以在没有任何 AI 工具的情况下重现此 PR 中包含的所有 AI 辅助内容。