mateclaw/mateclaw-ui/src/views
倪程伟 03a6d61131
feat(sso): 飞书 OAuth2 单点登录 (ISSUE #405 P0) (#419)
* feat(sso): feishu OAuth2 single sign-on (ISSUE #405 P0)

Implements the SSO design (ISSUE #405) with feishu as the first IdP
and a generic OAuth2 provider abstraction for future dingtalk/wecom
extensions. SSO is disabled by default — existing deployments are
unaffected until mateclaw.sso.enabled=true.

Backend:
- SsoProvider interface + SsoUserInfo record: generic IdP abstraction
- FeishuSsoProvider: OAuth2 authorization-code flow (app_access_token
  with Caffeine cache → user_access_token → user info). apiBase switches
  between feishu.cn / larksuite.com by domain config.
- SsoProviderRegistry: conditional registration, lists enabled providers
- SsoStateService: HMAC-signed OAuth2 state + self-contained bind_token
  JWT, both persisted to sso_state DB table for multi-node correctness.
  State is one-time-consumable (conditional UPDATE), bind_token jti
  anti-replay via PK insert. Hourly ShedLock purge (LambdaQuery + Java
  time, works on all 3 dialects).
- SsoService: authorize/callback/bind, user mapping (union_id first →
  external_id fallback), auto-create with concurrent idempotency
  (DuplicateKeyException → rollback orphan user → re-query), link-only
  mode issues bind_token for existing-account binding.
- SsoController: 4 endpoints (/providers, /authorize, /callback, /bind)
  all permitAll.
- V159 migration (h2/mysql/kingbase): mate_user_external_identity,
  sso_state, ALTER mate_user.password NULL (SSO-only users).
- AuthService: generateToken promoted to public; login() guards
  password=null (SSO-only users cannot password-login).
- SecurityConfig: /auth/sso/** added to permitAll whitelist.
- LoginRateLimitFilter: expanded to cover /auth/sso/bind (brute-force
  surface equivalent to /auth/login).
- application.yml: mateclaw.sso.* config block (all env-var driven).

Frontend:
- Login.vue: dynamic SSO buttons (only shown when providers configured),
  OAuth2 callback detection (?sso=callback), link-only bind dialog,
  shared applyLogin flow (localStorage + workspace + route).
- api/index.ts: ssoApi (providers, authorize, callback, bind).

Tests: SsoStateServiceTest (11) — state issue/verify/replay/tamper,
bind_token issue/verify/anti-replay/garbage. Regression: PAT (23) +
Approval resolve (13) all green.

Not in scope (P1/P2): link-only bind/unbind management endpoints,
user enable/disable endpoint, dingtalk/wecom providers, admin SSO
config page. Workspace assignment for auto-created users remains a
product decision (design doc §12 item 2).

* fix(sso): self-review fixes — P0 security + P1 quality

P0-1 BindRequired serialization: replaced the R.fail(200, Map.toString())
hack with a structured SsoCallbackResponse record. Controller no longer
catches an exception for a non-error path; frontend reads bindRequired
flag directly instead of regex-parsing a stringified map.

P0-2 createSsoUser unbounded recursion: added a retry flag — second
DuplicateKeyException (extreme race where identity was concurrently
deleted) now throws a 503 instead of recursing to stack overflow.

P0-3 state TTL not enforced: verifyState's conditional UPDATE now
includes created_at > cutoff, so a state unused for 5+ min is rejected
at consumption time, not just at the 1h purge. Without this the 5-min
window was advisory only.

P1-5 SsoStateService unused ObjectMapper: removed dead injection.

P1-6 audit JSON string concat: replaced with ObjectMapper serialization
(provider/externalId no longer risk breaking the JSON structure).

P1-7 LoginRateLimitFilter shared counter: documented the intentional
decision that login + bind share a per-IP counter (same brute-force
surface) with guidance on switching to per-path if finer isolation
is needed.
2026-06-26 10:00:31 +08:00
..
Agents/components feat(agents): open AGENTS.md editor in a modal, as a settings row, with section reordering 2026-06-08 21:00:07 +08:00
Docs feat(docs): structure the in-app help viewer to match the docs site 2026-06-22 17:28:35 +08:00
Doctor refactor(ui): share drawer chrome via MateDrawer, migrate Doctor and skill drawers 2026-05-15 10:19:16 +08:00
Enterprise fix(ui/enterprise): type filter keys so computed arrays match ref unions 2026-05-13 11:30:52 +08:00
layout feat(docs): expose bundled help docs via in-app viewer 2026-06-15 07:48:49 +08:00
mcp fix(mcp): refresh agent cache on MCP connection change + non-blocking connect (#289) 2026-06-09 14:14:08 +08:00
Memory feat(agents): open AGENTS.md editor in a modal, as a settings row, with section reordering 2026-06-08 21:00:07 +08:00
Onboarding feat(ui): dashboard model-config card + onboarding provider enablement 2026-05-16 14:51:41 +08:00
Scheduler feat(scheduler): unify cron jobs and triggers into a tabbed Scheduler page 2026-05-19 21:23:18 +08:00
Security polish(approval-grants-ui): fix active-count pill + reuse mcConfirm for revoke 2026-05-27 15:54:47 +08:00
Settings feat(skill): self-evolving skills — out-of-band reflection, curator consolidation, agent-authored skill files 2026-06-23 13:51:04 +08:00
Wiki feat(wiki): configurable entity types, type legend filter & theme-aligned graph colors (#336) 2026-06-19 07:18:09 +08:00
AcpEndpoints.vue refactor(ui): swap ElMessage for project-native mcToast, finish mcConfirm migration 2026-05-15 10:19:24 +08:00
AgentContext.vue refactor(ui): unify employee selector into shared AgentPickerDialog 2026-05-16 22:17:58 +08:00
AgentCreateWizard.vue feat(agent): one-sentence AI employee creation wizard 2026-06-17 17:38:42 +08:00
Agents.vue feat(plans): Kanban boards in the Agents workspace 2026-06-20 17:52:29 +08:00
Channels.vue refactor(ui): swap ElMessage for project-native mcToast, finish mcConfirm migration 2026-05-15 10:19:24 +08:00
ChatConsole.vue fix(chat): suppress 403 console spam from polling unpersisted conversations (ISSUE #408) 2026-06-25 14:36:59 +08:00
Dashboard.vue refactor(dashboard): componentize operational export, restore DB chip, polish export dialog 2026-06-24 18:38:01 +08:00
Datasources.vue refactor(ui): swap ElMessage for project-native mcToast, finish mcConfirm migration 2026-05-15 10:19:24 +08:00
Forbidden.vue feat(ui,router): gate routes and sidebar by workspace capability 2026-05-15 10:18:38 +08:00
Login.vue feat(sso): 飞书 OAuth2 单点登录 (ISSUE #405 P0) (#419) 2026-06-26 10:00:31 +08:00
McpServers.vue feat(tool,skill,ui): progressive tool/skill disclosure (load_skill + enable_tool + tier UI) 2026-05-23 09:07:45 +08:00
Plugins.vue refactor(ui): swap ElMessage for project-native mcToast, finish mcConfirm migration 2026-05-15 10:19:24 +08:00
Sessions.vue feat(sessions): paginate admin list, add back-nav, redesign with depth 2026-05-20 20:58:05 +08:00
SkillMarket.vue feat(tool,skill,ui): progressive tool/skill disclosure (load_skill + enable_tool + tier UI) 2026-05-23 09:07:45 +08:00
SkillTemplates.vue refactor(ui): swap ElMessage for project-native mcToast, finish mcConfirm migration 2026-05-15 10:19:24 +08:00
TokenUsage.vue refactor(ui): swap ElMessage for project-native mcToast, finish mcConfirm migration 2026-05-15 10:19:24 +08:00
Tools.vue fix(tool): show runtime names in tools admin 2026-05-23 22:54:57 +08:00
Workflows.vue fix(workflow): keep the editor canvas and status correct after publish 2026-05-18 17:34:53 +08:00