Skip to content

WebChat 多租户 spec ④:企业 SSO(OIDC 统一认证)#757

Merged
hrygo merged 6 commits into
mainfrom
feat/webchat-oauth-sso
Jun 18, 2026
Merged

WebChat 多租户 spec ④:企业 SSO(OIDC 统一认证)#757
hrygo merged 6 commits into
mainfrom
feat/webchat-oauth-sso

Conversation

@hrygo

@hrygo hrygo commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #756

标准 OIDC Authorization Code flow + PKCE,一个实现覆盖全部国内主流统一认证厂商(派拉/玉符/阿里云 IDaaS/腾讯云 IDaaS/宁盾/Authing/竹云/华为 OneAccess/TOPIAM)及国际 IdP(Keycloak/Okta/Azure AD/Google Workspace)。

核心组件

组件 文件 说明
OAuthProvider internal/security/oauth_provider.go OIDC 客户端(discovery + token exchange + ID Token 验证)
OAuthManager internal/security/oauth_manager.go 多 provider 注册表(支持热重载)
OAuthHandlers internal/gateway/oauth_handlers.go login / callback / providers HTTP 端点
State cookie internal/security/oauth_state.go HMAC 签名,CSRF + PKCE + provider 校验
user_identities migration 020 (provider, subject)user_id 唯一映射
Config internal/config/oauth_types.go oauth.providers[] 配置 + 验证

安全设计

  • Authorization Code flow + 强制 PKCE(S256) — 即使 code 被截获,无 verifier 也无法 exchange
  • State CSRF 防护 — HMAC 签名 cookie(5min TTL),state 绑定 provider
  • ID Token 验证 — JWKS 签名验证 + iss/aud/exp 校验(go-oidc 自动处理)
  • Provider 注入防护name 只允许 [a-z0-9-]+ + 注册表精确匹配
  • 不自动合并账号(provider, subject) 首次登录自动建号,email 不参与关联

与 spec ① 的关系

与密码登录并存,均为一等公民。顺带 wire spec ① 的 auth_handlers(routes.goTODO(spec ⑥) 解除)——spec ④ 交付后 WebChat 后端认证体系完整。

配置示例

oauth:
  external_url: "https://hotplex.example.com"
  providers:
    - name: "keycloak"
      display_name: "企业 SSO"
      issuer: "https://sso.example.com/realms/main"
      client_id: "hotplex"
      client_secret: "${OAUTH_KEYCLOAK_SECRET}"

测试(24 test,make quality 全绿)

测试 数量 覆盖
store identity 4 CRUD + UNIQUE 约束 + not found
state cookie 7 set/verify/CSRF/expired/tampered/missing/mismatch
config 10 validate/scopes/claims/callbackURL/duplicate/invalid
mock IdP 端到端 3 discovery → authURL → PKCE exchange → ID Token 验证 → claims 提取

mock IdP 测试使用 httptest.Server 模拟完整 OIDC provider(discovery + JWKS + token endpoint),用 RSA RS256 签名真实 JWT,验证 go-oidc 完整验证链路。

依赖

  • github.com/coreos/go-oidc/v3 v3.18.0(新增)
  • golang.org/x/oauth2 v0.36.0(indirect → direct)

Checklist

  • migration 020(SQLite + PG 双版本)
  • user_identities 表 + store 方法(SQLite + PG)
  • OAuthProvider OIDC 客户端
  • OAuthManager 多 provider 管理
  • State cookie 安全机制
  • OAuthHandlers HTTP 端点
  • Config 类型 + 验证
  • routes.go wire(auth + oauth)
  • gateway_run.go 初始化 OAuthManager
  • 单元测试 + mock IdP 集成测试
  • make quality 全绿

调研国内主流统一认证厂商(派拉/玉符/阿里云/腾讯云/宁盾/Authing/竹云/
华为 OneAccess/TOPIAM),确认 OIDC 是 100% 覆盖的最大公约数。

设计要点:
- 标准 OIDC Authorization Code flow + PKCE(一个实现覆盖全部厂商)
- 多 provider 配置(oauth.providers[]),独立于 bot 配置
- 与 spec ① 密码登录并存,均为一等公民
- 首次 SSO 登录自动建号(provider+subject→users),不自动合并
- user_identities 表解耦 OAuth 身份与 users(migration 020)
- go-oidc/v3 + golang.org/x/oauth2(已 indirect 在 go.mod)
- 安全:state CSRF 防护 + PKCE + ID Token 签名验证
- 顺带 wire spec ① auth_handlers(routes.go TODO(spec ⑥) 解除)
- spec ④ 不含前端 UI,归 spec ⑥
标准 OIDC Authorization Code flow + PKCE,一个实现覆盖全部国内主流统一认证
厂商(派拉/玉符/阿里云 IDaaS/腾讯云 IDaaS/宁盾/Authing/竹云/华为 OneAccess/
TOPIAM)及国际 IdP(Keycloak/Okta/Azure AD/Google Workspace)。

核心组件:
- OAuthProvider: OIDC 客户端(discovery + token exchange + ID Token 验证)
- OAuthManager: 多 provider 注册表(支持热重载)
- OAuthHandlers: login/callback/providers HTTP 端点
- user_identities 表(migration 020): (provider, subject) → user_id 映射
- State cookie: HMAC 签名,CSRF 防护 + PKCE 绑定 + provider 校验

安全设计:
- Authorization Code flow + 强制 PKCE(S256)
- State 参数 CSRF 防护(HMAC 签名 cookie,5min TTL)
- ID Token 签名验证(JWKS)+ iss/aud/exp 校验
- Provider name 注入防护([a-z0-9-]+ + 注册表查找)
- 不自动合并账号(首次 SSO 登录自动建号,provider+subject 唯一映射)

与 spec ① 密码登录并存,均为一等公民。顺带 wire spec ① auth_handlers
(routes.go TODO(spec ⑥) 解除)。

依赖:coreos/go-oidc/v3 + golang.org/x/oauth2(已 indirect → direct)

测试覆盖:
- store: identity CRUD + UNIQUE 约束(4 test)
- state cookie: set/verify/CSRF/expired/tampered/missing(7 test)
- config: validate/scopes/claims/callback URL(10 test)
- OAuthProvider: mock IdP 端到端 discovery→exchange→verify→claims(3 test)

make quality 全绿。
…grade warnings (#749)

- Bridge.resolveWorkspaceOverrides: dedup degrade warnings per workspaceID
  via sync.Map (LoadOrStore), re-arm on successful resolution — prevents
  log spam under high-crash session loops
- ScanWorkspaceOverrides: one-time startup sweep of all active workspaces'
  agent_config_overrides, logs Warn for invalid JSON written before spec ②
  write-time validation existed — non-blocking, no data modified
- ListAllWorkspaces: new store method (SQLite + PG) backing the startup scan
- Tests: warn dedup lifecycle, startup scan (nil/valid/dirty/error), store

Closes #749
P1: Make first-login user+identity creation idempotent. A prior crashed
first-login could leave an orphaned users row (CreateUser ok, identity
insert failed on transient DB error). On retry, re-check by the
deterministic 'provider:subject' username and reuse the existing row,
avoiding a UNIQUE(username) violation that permanently locked out the
SSO identity.

P2: Callback now checks for IdentityError{ErrCodeUserDisabled} via
errors.As and redirects to ?auth_error=USER_DISABLED instead of the
generic USER_CREATE_FAILED.
The SSO/OAuth landmine (spec ④) added oauth_manager.go (7 funcs) with no
tests, dropping internal/security coverage to 78.3% — below the CI 80%
threshold. Add oauth_manager_test.go covering all 7 functions and every
Reload branch (empty, success, clear, discovery error, partial error,
preserve-unchanged, rediscover-on-client_id-change). Reuses the existing
mockOIDCServer. Package coverage 78.1% → 84.8%, oauth_manager.go 0% → 100%.
@hrygo hrygo merged commit 4357d92 into main Jun 18, 2026
5 checks passed
@hrygo hrygo deleted the feat/webchat-oauth-sso branch June 18, 2026 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebChat 多租户 spec ④:企业 SSO(OIDC 统一认证)

2 participants