资讯动态

teams-for-linux 第三方 IdP 一次性验证码(OTC)预填为何被否决:ADR-028 决策全过程解析

发布时间:2026/10/14 22:18:51 来源:尧图企业网站定制
桌面应用即时通讯【免费下载链接】teams-for-linuxUnofficial Microsoft Teams for Linux client项目地址https://gitcode.com/gh_mirrors/te/teams-for-linux点击查看免费下载本文基于 teams-for-linux 仓库的架构决策记录 ADR 028完整剖析一次已被否决的认证增强方案为第三方身份提供商如 Okta的一次性验证码One-Time-CodeOTC字段实现自动预填。文章不仅还原了该 ADR 的上下文、备选方案与最终结论还结合仓库中auth.webLogin.*的实际实现app/ssoPasswordPrefill/index.js与相关测试tests/unit/ssoPasswordPrefill.test.js讲清楚「为什么密码可以预填、验证码却不行」以及「减少凭据输入的正确方向是什么」。读者读完将掌握Web 登录预填功能的真实能力边界、Electron 无法托管密码管理器扩展的技术根因以及当前项目支持 FIDO2、智能卡、Intune SSO 等「有契约」认证方式的具体配置方法。一、决策状态与背景来自真实用户的一次请求ADR-028 的状态是❌ Rejected已否决调查发生于 2026 年 8 月尝试实现于 PR #2874。它并非凭空出现的架构空想而是由一个真实用户诉求issue #2869驱动用户请求一个totpCommand作为已随应用发布的auth.webLogin.passwordCommand的姊妹功能——既然密码可以从密码管理器以命令方式取出并填入登录框那么认证器authenticator生成的动态验证码也应该能走同样的路径。这个诉求的诱因很普遍很多企业如联合国等机构通过策略让 Teams 会话频繁过期用户几乎每次启动都落在微软/联合federated网页登录页上不得不反复输入凭据。项目已有的auth.webLogin.passwordCommand正是为解决这一痛点而生它允许用户配置一条 shell 命令例如pass show teams把密码管理器的输出直接填入密码框应用本身不存储任何秘密。为什么密码能预填而验证码不行密码侧能成立的根本原因非常朴素input[typepassword]几乎是所有登录表单的通用事实标准。无论微软的 Entra 登录页如何变化密码字段的类型标识基本稳定因此基于选择器selector的注入在绝大多数场景都可靠。一次性验证码字段则完全不同。它没有统一的 DOM 形态微软 Entra 的汇聚式验证码页面使用input[nameotc]、#idTxtBx_SAOTCC_OTC这类选择器Okta Identity Engine 则使用input[namecredentials.totp]为了覆盖其他情况当时的尝试还设计了auth.webLogin.totpSelector作为「逃生舱」配置项。也就是说实现方不得不为每家 IdP、甚至每个页面版本维护一套专用选择器。正是这种「为未知形态的 DOM 编写猜测代码」的做法为后续的失败埋下了伏笔。真实案例Okta 三屏流程下预填彻底失效ADR 记录了一个极具说服力的实证报告人所在的组织使用 Okta登录要依次经过三个相互独立的界面——身份识别identify、Verify with your password密码校验、Enter code from Okta Verify app输入 Okta Verify 应用生成的验证码。即使在把用户的确切字段名加入内置选择器列表之后验证码步骤依然从未被填充过。这意味着问题不是「选择器写错了」这么简单而是 Okta 的渲染行为、页面生命周期或事件绑定机制导致注入脚本根本没能把值写进去对一个无法在生产环境复现、无法穷举租户定制情况的 DOM 进行逆向维护成本不可控。二、正式决策不追求第三方 IdP 的 OTC 预填基于上述事实ADR-028 的结论非常明确不针对第三方身份提供商实现一次性验证码预填。auth.webLogin.user与auth.webLogin.passwordCommand继续为它们所构建的微软托管登录页提供支持。这一决策的实质是划定能力边界现有的 web 登录预填功能只承诺覆盖微软托管登录域login.microsoftonline.com、login.microsoft.com、login.live.com不对第三方 IdP 的私有标记语言负责。仓库中 app/ssoPasswordPrefill/index.js 的内置登录主机常量与 app/config/options.js 的auth.webLogin.*默认值全部为空/关闭都印证了这一点预填是默认不启用、需要用户显式配置的增强功能且其宿主范围是明确受限的。支撑决策的配置现状可作为对照在 docs-site/docs/configuration.md 中auth.webLogin的完整配置面如下选项类型默认值说明auth.webLogin.userstring邮箱/用户名在账户字段为空时预填。为空则禁用。auth.webLogin.passwordCommandstringshell 命令其 stdout 首行被预填进密码字段。为空则禁用。auth.webLogin.extraHostsarray[]除内置微软主机外额外视为登录页的主机后缀。联合 IdP 的登录页不在微软域名下时添加。auth.webLogin.autoSubmitbooleanfalse自动推进邮箱步后点 Next、密码步后点 Sign in。auth.webLogin.verifyMethodstring在 Verify your identity MFA 页面点击标签以此文本开头的选项如Text对应短信。典型config.json示例来自 app/ssoPasswordPrefill/README.md{ auth: { webLogin: { user: youexample.org, passwordCommand: pass show work/teams, autoSubmit: true, verifyMethod: Text } } }注意auth.webLogin.verifyMethod只做「点击 MFA 方式选择」这一件事它不会替你输入验证码——MFA 页面选好方式后弹出的验证码仍须手动键入。这恰好与 ADR-028 的边界相呼应预填链条覆盖到「选择验证方式」为止验证码本身不在承诺范围内。三、被否决的备选方案一按租户做选择器匹配第一个被考虑的方案是继续沿着选择器路线走下去——为每个租户/IdP 维护精确的字段选择器。ADR 给出了三条扎实的否决理由1. Okta 刻意禁用了自动填充Okta 的登录组件在验证码字段上刻意设置了autocompleteoff。okta-signin-widget 中请求支持自动填充和密码管理器集成的问题#1119已经挂了多年且无任何进展这证明它是一个立场而非疏漏——对第二因素2FA而言这是一个站得住脚的安全选择。任何基于浏览器自动填充能力的方案从源头就被掐断了。2. 元素标识符每次渲染都会变化无契约可言元素 id 是每次渲染动态生成的报告中出现的真实 id 是input54这种随机形态唯一稳定可用的只剩name属性而它只是 widget 的内部字段键不携带任何兼容性契约每个租户都可以自定义customiseOkta widget标记结构随时可能漂移。「追逐这种标记」是一场必输的跑步机a treadmill we would lose——今天修好的选择器明天可能在某个租户的定制主题下再次失配。3. 每次失配在用户眼里都是一次「回归」这是最关键的用户体验维度预填功能一旦存在用户就会把它当作承诺。当某个租户页面上验证码没有被填充时用户感知到的不是「此功能不支持这个 IdP」而是「功能坏了」。这种不可控的「假回归」噪音是维护方最不愿意背上的包袱。实现层佐证现有预填如何做安全门控从源码可以更具体地理解「选择器方案」的脆弱性。现有密码预填的注入门控isLoginUrlapp/ssoPasswordPrefill/index.js做了双重校验协议必须是 HTTPS且主机名必须命中内置或extraHosts提供的主机后缀。其单元测试tests/unit/ssoPasswordPrefill.test.js覆盖了内置微软主机在 HTTPS 下匹配成功子域如eu.login.microsoftonline.com匹配http://明文连接即使主机匹配也被拒绝形似主机login.microsoftonline.com.evil.com被拒绝extraHosts生效但仍要求 HTTPS。这些测试证明了现有实现把「往哪注入」作为安全边界在严加防守而 OTC 预填若要做成就得在「往什么字段注入」上对不可信的第三方 DOM 做出同样的承诺——这是现有架构无力提供的。四、被否决的备选方案二加载密码管理器浏览器扩展选择器方案之外最「显而易见」的出路是让真正的密码管理器去完成填充——即把 1Password、KeePassXC、Bitwarden 等桌面版的浏览器扩展装进 Electron。ADR 明确指出Electron 无法托管这类扩展理由环环相扣chrome.runtime.connectNative不在支持面内Electron 支持的chrome.*API 表面并不包含 native messaging。而 native messaging 恰恰是 1Password、KeePassXC、Bitwarden 桌面集成连接本地 vault密码库的通道——扩展正是靠它才能和持有秘密的桌面应用通信。加载方式受限Electron 只加载 unpacked未打包扩展不支持.crx签名包。存储受限仅支持chrome.storage.local。无 UI 概念Electron 没有 popup弹出面板和 extension actions工具栏按钮的概念意味着连一个让用户点击「填充」的工具栏界面都不存在。这个「墙」不是 ADR-028 首次撞上。它同样是 #2609关于密码管理器集成及其 spike #2610 背后的同一堵墙。ADR 还特别指出了 allowlist 方案的无效性在/etc/1password/custom_allowed_browsers中把我们自己的二进制加入白名单只能控制 1Password 应用愿意通过「扩展→应用」通道与哪些浏览器对话如果没有能使用 native messaging 的扩展光靠 allowlist 几乎不可能有任何效果。事实佐证同样有力自 #2609 提出该问题以来没有任何人确认过自动填充快捷键能在 Electron 窗口内完成填充。五、被否决的备选方案三直接驱动 IdP 的 API第三条路是绕开 DOM直接调用身份提供商的 API 完成验证码认证Okta 的 Interaction Code grant交互码授权这是面向「拥有 Okta 关系」的应用设计的现代授权流要求在每个客户的组织内完成一次应用注册app registration。而 teams-for-linux 只是包装 Microsoft Teams 的客户端从不拥有也不应拥有与客户 Okta org 之间的这种关系——让每个租户都为第三方客户端注册应用推广成本与合作成本都不可接受。经典的/api/v1/authnsessionToken 路由已被标记为过时并处于退役流程中superseded and being retired把方案建立在一条正在消失的 API 上毫无意义。这一备选方案的否决进一步夯实了总决策任何需要「拥有 IdP 关系」的方案都不适合一个包装型客户端。六、后果与出路有契约的认证方法才是正解被否决并不等于「问题不存在」。ADR 的 Consequences 部分给出了明确的建设性指引想要更少凭据提示的用户应当改用真正有契约contract支撑的认证方法——即认证流程由标准组织或协议定义、而非靠抓取页面标记实现。项目当前已经支持的三条路线分别是1. FIDO2 / WebAuthn 硬件安全密钥auth.webauthn.enabled对应 ADR 021。WebAuthn 是 W3C 标准 APInavigator.credentials不是被爬取的标记scraped markup。在 Linux 上项目通过两层navigator.credentialsmonkey-patch把硬件密钥仪式转交给发行版自带的fido2-tools命令行套件fido2-cred/fido2-assert完成实现在 app/webauthn/index.js 与 app/webauthn/fido2Backend.js。配置方式{ auth: { webauthn: { enabled: true } } }要求系统装有fido2-toolsDebian/Ubuntusudo apt install fido2-toolsFedorasudo dnf install fido2-toolsArchsudo pacman -S libfido2。对联邦租户而言尤其相关的是auth.webauthn.extraOrigins当 FIDO2 提示不在微软登录域名下、而是由客户自己的 IdP 提供时可将该 IdP 的精确 HTTPS origin含端口加入白名单实现在 app/webauthn/originAllowlist.js配置示例见 docs-site/docs/configuration.md。这正是一条「第三方 IdP 场景下依然有契约可循」的替代路径。2. 智能卡 / PKCS#11 客户端证书auth.clientCertificate.pinDialog.enabled对应 ADR 024。国家 eID 卡、PIV/CAC 卡、PIV 模式下的 YubiKey 等硬件证书是企业和政府用户的刚需。Linux 上 Chromium 无原生 PIN 提示 UI项目通过app.setClientCertRequestPasswordHandler实现在 app/clientCertificate/index.js配合独立加固的 PIN 输入窗口 app/_shared/securePrompt.js 完成解锁——PIN 只存在于主进程持有的独立窗口中绝不注入 Teams 页面。配置{ auth: { clientCertificate: { pinDialog: { enabled: true } } } }该功能仅限 Linux、默认关闭且要求用户自行完成 PKCS#11 模块注册如modutil -dbdir sql:$HOME/.pki/nssdb -add opensc -libfile ...。3. Intune SSOauth.intune.enabled走 Microsoft Identity Broker 的 D-Bus 通道实现在 app/intune/index.js是另一条契约化的单点登录路径配置见 docs-site/docs/configuration.md。最有效的改变往往不在这个应用里ADR 特别强调了一个经常被忽略的事实对多数用户而言减少验证码输入的最有效手段是组织策略层面的事而不是客户端的事Okta Verify push推送确认代替输入验证码remember this device记住此设备免除重复验证FastPassOkta 的无密码/生物识别通行证。这三者都直接消除验证码输入环节且都是组织策略可以一键开启的能力。七、给未来贡献者的遗产从已知死胡同出发ADR 的最后一段点明了这份否决记录的价值如果一个未来贡献者想为稳定的内部 IdPin-house IdP重新实现基于选择器的预填这并不困难。本记录存在的意义就是让后续工作从已知的死胡同出发而不是重新把它们踩一遍。这揭示了 ADR 机制的核心价值记录被否决的路径和记录被采纳的路径同等重要。对于「稳定的内部 IdP」——即由企业自己维护、标记结构可控、不会像 Okta 那样每次渲染生成随机 id 的身份平台——选择器式预填依然是一个完全合理的可执行方向ADR-028 为其划清了边界并沉淀了反模式清单不要假设autocomplete会可用Okta 是刻意关闭的不要依赖元素 id每次渲染变化无契约不要在没有「扩展→应用」native messaging 通道的 Electron 里指望密码管理器扩展不要在包装型客户端里引入需要租户注册的 IdP API 依赖每一次失配都会被用户感知为回归选择器方案的承诺必须与维护成本一起评估。八、总结能力边界即产品边界ADR-028 是一次「主动说不」的架构决策它给 teams-for-linux 的认证体系划定了清晰的分层场景方案契约来源状态微软托管登录页免重复输入密码auth.webLogin.passwordCommanduser通用input[typepassword]事实标准✅ 已实现微软托管登录页自动推进 选 MFA 方式auth.webLogin.autoSubmit/verifyMethod微软登录页 DOM✅ 已实现best-effort第三方 IdP 的验证码自动填充totpCommand/totpSelector无各家 IdP 私有标记❌ 已否决硬件安全密钥auth.webauthn.enabledW3C WebAuthn 标准✅ 已实现Linux opt-in beta智能卡客户端证书auth.clientCertificate.pinDialog.enabledPKCS#11 / NSS✅ 已实现Phase 1组织级免验证码Okta Verify push / FastPass / remember-device组织策略建议用户在租户侧开启一句话结论把凭据交给「有契约的标准」WebAuthn、PKCS#11、Intune Broker而不是交给「被爬取的 DOM 标记」既是安全上的正确选择也是维护成本上的必然选择。ADR-028 为整个项目以及未来可能接入的内部 IdP 方案留下了可复用的判断框架任何预填/自动填充功能只有当注入目标拥有可验证、可承诺的稳定性时才值得实现。对于开发者而言理解这份被否决的 ADR等于同时理解了「为什么不这么做」和「应该怎么做」——而这正是阅读架构决策记录的最大价值。延伸阅读本文所依的原始记录 ADR 028 位于仓库 docs-site/docs/development/adr 目录同目录下的 ADR 021 与 ADR 024 记录了本文提及的两条已实现替代路线auth.webLogin的完整配置说明见 docs-site/docs/configuration.md实现与单元测试分别见 app/ssoPasswordPrefill/index.js 与 tests/unit/ssoPasswordPrefill.test.js。赞分享桌面应用即时通讯【免费下载链接】teams-for-linuxUnofficial Microsoft Teams for Linux client项目地址https://gitcode.com/gh_mirrors/te/teams-for-linux点击查看免费下载相关推荐teams-for-linux 性能审计10 项性能敏感点的决策归档与源码验证ADR-026teams for linux 性能审计10 项性能敏感点的决策归档与源码验证ADR 026 导读 本文基于 teams for linux 仓库中的架构桌面应用即时通讯teams-for-linux 屏幕共享架构决策实录为何拒绝 Electron 38 的 useSystemPickerADR-008 深度解析teams for linux 屏幕共享架构决策实录为何拒绝 Electron 38 的 useSystemPickerADR 008 深度解析 本文以桌面应用即时通讯teams-for-linux 为什么在 Wayland 会话中默认坚持 --ozone-platformx11ADR 031 决策全文解析teams for linux 为什么在 Wayland 会话中默认坚持 ozone platformx11 ADR 031 决策全文解析 导读 本文基于桌面应用即时通讯创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑