本卡屬 FR-166(母卡 CM-3109 延伸),決策者 2026-10-28 手測後推翻 CM-3184 的做法。Repo:evidence-agent。不依賴別張卡;CM-3189(登入頁提示文字)要配合改字,首腦已在那張卡 append。
白話
決策者在主系統是用 AD 帳號(jedicogy\raymond)登入的,到主控台 AD 分頁照樣填 AD 帳號,卻被擋「不在名單」。原因是 CM-3184 做成「帳號欄要填主系統帳號 blsadmin,Agent 再拿它查綁定的 AD 帳號去問 AD」——方向跟主系統相反,使用者一定填錯。要改成跟主系統一樣:帳號欄填 AD 帳號,Agent 拿它到名單裡反查「誰綁了這個 AD 帳號」,查到主系統帳號(blsadmin)再用那人的範圍登入。
資料面不用動:CM-3183 下發的名單已帶 ad_account(主系統綁定),Agent SQLite offline_operators 也存了(v5)。只是查的方向要反過來。
問題在哪
- core/console/local_auth.py verify():先 operator_listed(sub) 用 sub 當主系統帳號查名單;AD 分頁的 sub 是 AD 帳號,查不到 → not_listed,根本沒打 AD。本機 log 實證:四次 sub=jedicogy\raymond 全部 reason=not_listed。
- core/offline_operators.py:只有 get(sub) 按主系統帳號查;沒有「按 ad_account 反查」。
- 大小寫與網域:使用者打 jedicogy\raymond,主系統存的是 JEDICOGY\raymond(jedi-ldap DirectoryUser.username 照 AD 回的 sAMAccountName 組);也可能只打 raymond 不帶網域。
怎麼做
- 【new】offline_operators.get_by_ad_account(account) → Operator|None:比對時雙方都正規化——去頭尾空白、網域與帳號分開後各自 casefold;輸入沒帶網域時,只在「名單內只有一個人的 ad_account 帳號部分相同」才命中,兩個以上就當找不到(不猜)。SQLite 查全表再在 Python 比(名單最多 MAX_OPERATORS 筆,不加索引)。
- 【extend】local_auth.verify:method=ldap 時 sub 視為 AD 帳號:op = get_by_ad_account(sub);op 為 None → FAILED、reason=not_listed(log 寫 ad_account=…,不寫密碼);之後 operator_session_valid 與 _check_operator 都用 op.sub(主系統帳號),ldap_source.login_check 用 op.ad_account 問 AD(CM-3184 已改好那段,照用)。回傳的 AuthResult.sub 是 op.sub(主系統帳號,稽核與 session 都認這個),display_name 照名單。
- 【保留】method=password(離線密碼)仍填主系統帳號、走 operator_listed(sub),不動。本機管理員 local-admin 不動。
- 【拿掉】CM-3184 在 verify 裡「AD 分頁帳號=主系統帳號」的那條路,不留雙路徑(AD 帳號反查失敗就是失敗,不再退回用 sub 當主系統帳號查一次——那會讓同一個輸入有兩種意思)。
- 【/api/me】回的 sub 是主系統帳號、另帶 login_account(使用者實際輸入的 AD 帳號,顯示用),前端側欄照舊顯示 display_name。
改哪些檔
- core/offline_operators.py(180 行)、core/console/local_auth.py(111 行)、core/console/local_auth_routes.py(401 那句 log 帶 reason,已有)
- test/test_console_local_login.py、test/test_ldap_source.py
驗證
- 單元:名單 blsadmin.ad_account=JEDICOGY\raymond 時,method=ldap sub=jedicogy\raymond/JEDICOGY\raymond/raymond 都反查到 blsadmin 並拿 JEDICOGY\raymond 問 AD;sub=blsadmin 走 AD 分頁 → not_listed(主系統帳號不是 AD 帳號);兩人 ad_account 帳號部分同名、輸入不帶網域 → not_listed;method=password sub=blsadmin 照舊。突變:拿掉 casefold → 小寫那支紅;反查改回 get(sub) → 第一支紅。
- 本機實測:主控台 AD 分頁帳號填 jedicogy\raymond、密碼填 AD 密碼 → 登入成功,側欄顯示 Billows系統管理員,稽核 login sub=blsadmin method=ldap;錯密碼 → 401、log reason=credential_rejected;帳號填 blsadmin 走 AD 分頁 → 401、reason=not_listed。