[Feature] Canopy auth 1/2: local auth — auth config, argon2id login, server-side sessions, API tokens
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 35/100
- Loại issue
- Tính năng
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- node.js, typescript, yaml
- Lĩnh vực
- api, authentication, backend, security
Hướng nghiên cứu
Start with canopy/server/src/config.ts, canopy/server/src/routes/auth.ts, canopy/server/src/plugins/session.ts, and the cited Horizon BFF files to map the existing auth flow. Then read the Canopy server tests and README. The issue defines acceptance cases for config, password verification, sessions, tokens, and compatibility; done means those cases and the stated build, license, and e2e requirements pass.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary (executable leaf 1/2 of #14001)
Canopy's local authentication, following SkyWalking Horizon UI (apache/skywalking-horizon-ui main, apps/bff/src/user/{local,sessions,middleware,tokens}.ts, apps/bff/src/config/schema.ts). It has three parts:
- Part 1: the
authconfig with thelocalbackend and argon2id passwords. - Part 2: a server-side session store with the auth middleware.
- Part 3: API tokens.
Nothing here needs an identity provider. SSO, break-glass and the design doc are leaf 2/2.
Current behavior (BanyanDB origin/main @ 450c73a3)
canopy/server/src/config.tsloadUsersreadsCANOPY_USERS(a JSON/YAML file) and throws unless it is a non-empty array.CANOPY_DEV_NOAUTH=truecreatesadmin/admin.canopy/server/src/routes/auth.tsPOST /auth/loginverifies passwords withbcryptjs. A fixed invalid bcrypt hash keeps the timing of unknown users close to known ones.- Roles are
admin|readonly(lib/role.ts).
canopy/server/src/plugins/session.ts registers @fastify/secure-session: the whole session (user, role, banyanVersion) is encrypted into the cookie, with httpOnly, sameSite: 'strict', secure: 'auto' and a fixed 8 h maxAge. Logout deletes the cookie but cannot revoke a copied one, and role changes in config only apply after re-login.
Part 1: auth config, local backend, argon2id
- Config: an
authsection, loaded fromCANOPY_AUTH_CONFIG(YAML/JSON file) withCANOPY_AUTH_*env overrides, using Horizon's key names:auth.backend(local|sso, defaultssoper #14001; this leaf implementslocalonly, andssofails at startup with "not yet supported" until leaf 2/2 (#14162)) andauth.local.users[]({username, passwordHash, role}, default[]). Validate it with clear startup errors. - No default admin.
auth.backend: localwithusers: []boots cleanly, and every login is refused.CANOPY_DEV_NOAUTHkeeps its current dev-only behavior and stays forbidden in production. - argon2id verification with Horizon's dummy-hash timing equalization: an unknown user still runs one argon2id verify against a fixed dummy hash.
Implementation constraint: no native module. Use a pure-JS/WASM argon2id (e.g.hash-wasmargon2Verify) that accepts the standard PHC string ($argon2id$v=19$m=…,t=…,p=…$salt$hash) that Horizon's nativeargon2produces, so hashes are portable between the two UIs. This keeps the macOS-ARM build that apache/skywalking-banyandb#1389 fixed by dropping platform-pinned native binaries. - Compatibility:
CANOPY_USERSkeeps working as an alias forauth.local.users. Existing bcrypt ($2a$/$2b$/$2y$) hashes still verify, with one startup WARN per bcrypt user naming the username and saying to rehash with argon2id. Document a one-line way to produce an argon2id hash. - Map roles inside the BFF: Canopy keeps
admin/readonly. Accept Horizon'sviewer→readonlyandmaintainer/operator/admin→adminin config, and record the mapping in one place.
Part 2: server-side sessions and middleware
- An in-memory session store keyed by a random id (≥128 bits) in a Horizon-style cookie (
session.cookieName, defaultcanopy_sid;httpOnly,sameSite: 'strict',secure: session.cookieSecuredefault true outside dev,path= Canopy base path). Sliding expiry:session.ttlMinutes, default 60, extended on use. The store holds the username only. - Middleware
requireAuth, plusrequireBrowserSessionfor browser-only routes. It resolves the principal in Horizon's order, of which only the cookie step exists in this leaf; keep an explicit extension point for the bearer steps of Part 3 and leaf 2/2. It re-resolves the role from the current config on every request, so removing a user or changing a role takes effect without re-login. POST /auth/logoutremoves the session server-side; the old cookie value then gets 401.- Keep the routes' response shapes (
/auth/login,/auth/session,/auth/logout) unchanged for the web app.
Part 3: API tokens
auth.tokensFile(YAML/JSON): entries{id, username, secretHash, description?}, wheresecretHashis SHA-256 hex of the secret. Token formathzn_<id>_<secret>, kept verbatim for parity with Horizon.Authorization: Bearer hzn_…is resolved in Part 2's middleware before the cookie: parse, look upid, compare SHA-256 of the secret in constant time, then resolve the username to a user and its current role. A token names a principal, never a role set.- Role re-resolution for bearers is cached 30 s on success and never cached on failure, as in Horizon. Deleting the local user revokes the token without editing the tokens file, within the cache window.
- Tokens never create a cookie session. Routes marked
requireBrowserSession(login/logout) reject bearer-only callers. - A small CLI or README recipe to mint a token (prints the token once, writes the hash entry).
Concrete oracle
Part 1
auth: {backend: local, local: {users: []}}→ server starts;POST /auth/login {alice, x}→ 401invalid_credentials.- User
alicewith argon2id hash ofs3cret, roleviewer→ logins3cretsucceeds with rolereadonly;wrong→ 401. - User
bobwith a bcrypt hash → login succeeds, and the log has exactly one WARN aboutbob. - Unknown user → argon2id verify still runs once (spy or counter), and the response matches a wrong-password response.
auth.backend: sso→ startup error "sso backend not yet supported".
Part 2
- Login → cookie
canopy_sidwith the attributes above.GET /auth/sessionwith it → 200 with user and role. - Same cookie after logout → 401.
- Change
alice's role fromadmintoreadonlyin config (reload hook in tests) → the next write request with the existing session → 403. Removealice→ next request 401. ttlMinutes: 1with a fake clock: idle 61 s → 401; requests every 50 s keep it alive.
Part 3
- Valid
hzn_t1_<s>foralice(admin) →GETproxy route 200,POST200. Forbob(readonly) →POST403. - Wrong secret, unknown id or malformed token → 401, with the same response for all three.
- Remove
alicefrom users → after the cache window (fake clock 31 s) → 401. A failed lookup isn't cached: re-adding her works on the next request. - A request with both a valid bearer and a cookie for a different user → the bearer's principal wins.
Acceptance criteria
- Vitest tests in
canopy/server/testcover every oracle line through the Fastify app (app.inject), with fake timers for TTL and cache windows and log capture where the oracle checks logs. - No native dependency is added.
npm lsshows nonode-gyp/prebuilt binary package new to the tree. Unused@fastify/secure-sessionandbcryptjs-only code paths are removed, and the license artifacts are regenerated (make license-dep). - Token secrets never appear in logs, and token comparison uses
crypto.timingSafeEqual. - Existing Canopy server/web tests and the e2e login flow pass. Existing
CANOPY_USERS+ bcrypt deployments keep logging in. -
canopy/README.mdcovers theauth.*andsession.*keys andCANOPY_AUTH_CONFIG, the role mapping, how to make an argon2id hash, the tokens file format and token minting, and that sessions don't survive a restart.
Out of scope (leaf 2/2)
SSO (OIDC/OAuth2), break-glass, canopy/docs/auth-design.md, persistent or shared session stores, token expiry/rotation UI.
- Ngôn ngữ chính
- Java
- Star
- 25k
- Fork
- 6.6k
- Merge trung bình
- 14 giờ 48 phút
- Pull request đã merge (30 ngày)
- 31
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của apache/skywalking
-
[Bug] BanyanDB stream scans run out of query memory even with a small limitCó thể đã có người làm @hanahmily đã nhận hôm nay. Đang mởbug database
apache/skywalking#14165 · 1 bình luận · 2 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
database feature
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 20/100
apache/skywalking#14162 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
apache/skywalking#14158 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
database
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 58/100
apache/skywalking#14157 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
database
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
apache/skywalking#14104 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của apache/skywalking
Issue tương tự
-
dev/release: verify-release-candidate.sh runs 0 Java tests with Debian's MavenCó thể đã có người làm @kou đã nhận hôm nay. Đang mởType: bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
apache/arrow-adbc#4947 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
lysine-dev/okhttp#9814 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
1.20.1-FORGE bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
MehVahdJukaar/WoodGood#1348 ·
-
documentation faq
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100