Skip to content

[Feature] Adopt SkyWalking Horizon UI auth model in Canopy (SSO + local + API tokens) #14001

Description

@hanahmily

Summary

Bring Canopy's authentication model in line with SkyWalking Horizon UI (apache/skywalking-horizon-ui): one auth.backend selector with local, sso (OIDC / OAuth2), and an API-tokens file, plus a break-glass emergency path. Keep Canopy's existing session shape and role check; reuse Horizon's config schema verbatim so operators get one mental model across both UIs.

Background

Canopy currently supports only local users (configured via CANOPY_USERS as JSON/YAML) with two roles: admin and readonly. Horizon has a richer and battle-tested model: local / SSO (OIDC + OAuth2) / API tokens, optional break-glass, sliding cookie sessions, and 13 RBAC verbs gated per route. Adopting that model — instead of inventing a separate LDAP flow — means Canopy benefits from the same security hardening (dummy-hash timing equalization, scope intersection, role re-resolution) and the same configuration vocabulary.

Reference implementation

Repo: https://github.com/apache/skywalking-horizon-ui (default branch main).

Concrete files to mirror (Horizon → Canopy):

Horizon concept Horizon file Reuse strategy
Backend dispatch (local / sso / break-glass) apps/bff/src/http/user.ts Same dispatcher pattern in canopy/server/src/routes/auth.ts
Local argon2id login (with dummy-hash timing) apps/bff/src/user/local.ts Replace server/src/routes/auth.ts bcrypt path with argon2id
SSO/OIDC identity mapping apps/bff/src/user/oidc/identity.ts New canopy/server/src/auth/oidc.ts
API tokens (SHA-256, hzn_ prefix, re-resolved roles) apps/bff/src/user/tokens.ts New canopy/server/src/auth/tokens.ts
Session middleware (cookie + bearer resolution order) apps/bff/src/user/middleware.ts Extend canopy/server/src/plugins/session.ts
In-memory session store apps/bff/src/user/sessions.ts Replace current session impl
Cookie defaults (horizon_sid, cookieSecure, ttlMinutes: 60) apps/bff/src/config/schema.ts (sessionSchema) Use the same defaults
Three-variant Verified<T> audit taxonomy apps/bff/src/user/outcome.ts Copy the shape into Canopy
Config schema (auth.local, auth.sso, auth.breakGlass, auth.tokensFile) apps/bff/src/config/schema.ts Reuse keys verbatim

Goals

  • auth.backend selector: local | sso (default).
  • auth.local.users[] with argon2id password hashes, defaulting to empty.
  • auth.sso.providers[] for OIDC (e.g. Google) and OAuth2 (e.g. GitHub) — same provider shape Horizon uses.
  • auth.sso.roles with defaultRoles + roleByEmail (exact-match) + roleByDomain.
  • auth.tokensFile for API tokens with SHA-256 secrets + bearer header (Authorization: Bearer hzn_...).
  • Optional auth.breakGlass — only honored when SSO backend reports unhealthy.
  • Keep Canopy's existing admin / readonly role names; map Horizon's viewer/maintainer/operator/admin → Canopy roles inside the BFF.

Tasks

  1. Research — read Horizon's apps/bff/src/user/, apps/bff/src/http/user.ts, and apps/bff/src/config/schema.ts; document Canopy's current server/src/routes/auth.ts, server/src/plugins/session.ts, server/src/lib/role.ts.
  2. Design doc — canopy/docs/auth-design.md covering:
    • Config schema (copy Horizon's authSchema shape).
    • Session cookie + bearer resolution order: OAuth token → API token → cookie session (Horizon order).
    • Role re-resolution for bearers (cache 30s success, never cache failure).
    • Username-as-credential-anchor: tokens name a principal, never a role set.
    • Break-glass gating by SSO health probe.
  3. PoC — implement, mirroring Horizon file-by-file:
    • canopy/server/src/auth/local.ts — argon2id + dummy-hash timing.
    • canopy/server/src/auth/oidc.ts — OIDC + OAuth2 providers.
    • canopy/server/src/auth/tokens.ts — hzn_ tokens, SHA-256, bearer.
    • canopy/server/src/auth/sessions.ts — in-memory store.
    • canopy/server/src/auth/middleware.ts — requireAuth, requireBrowserSession.
    • canopy/server/src/http/auth.ts — /api/auth/login, /api/auth/me, /api/auth/logout, OIDC routes.
    • canopy/server/src/config.ts — extend loader for auth.* + session.* + rbac.*.
  4. Tests — unit tests for each auth backend using mocks (no live IdP); integration test for the bearer-resolution order; tests covering: timing equalization, scope intersection, role re-resolution, break-glass gating.
  5. Docs — update canopy/README.md with the new env vars (Horizon-style HORIZON_AUTH_* names kept as CANOPY_AUTH_* for clarity); add canopy/docs/auth-design.md; remove any old LDAP-centric notes from prior docs.

Acceptance Criteria

  • auth.backend: local with local.users: [] boots cleanly; no default admin.
  • auth.backend: local with users set issues a horizon_sid-style cookie (httpOnly, sameSite: 'strict', secure: cookieSecure()).
  • auth.backend: sso with a single GitHub OAuth2 provider works end-to-end (login → consent screen → role resolution via roleByEmail).
  • API tokens (hzn_<id>_<secret>, SHA-256 hashed in tokensFile) authenticate via Authorization: Bearer ...; deleting the local user revokes the token without editing the file.
  • Break-glass local admin is honored only when SSO is configured and the SSO health probe fails; every break-glass success logs at WARN with username + IP.
  • All existing Canopy e2e tests still pass under auth.backend: local with one configured admin.
  • canopy/README.md and canopy/docs/auth-design.md updated.

Out of Scope

  • LDAP / SAML (deferred — Horizon does not use it as the primary path either; add later if a user asks).
  • Multi-IdP / failover.
  • OAuth2.1 server (issuing tokens to MCP clients) — separate issue.
  • Password rotation / self-service.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    databaseBanyanDB - SkyWalking native databasefeatureNew feature

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions