☰
Apereo CAS 集成 Duo Security 双因素认证:配置、Universal Prompt 与无浏览器 MFA 实战指南
2026/10/15 18:28:16 网站建设 项目流程
  • 后端
  • 认证鉴权
  • 单点登录

【免费下载链接】cas

Apereo CAS - Identity & Single Sign On for all earthlings and beyond.

项目地址:https://gitcode.com/gh_mirrors/ca/cas
点击查看免费下载

导读

本文基于 Apereo CAS 官方文档与仓库源码,系统讲解如何将 Duo Security 两步验证服务接入 CAS 的多因素认证(MFA)体系。你将掌握cas-server-support-duo模块的核心配置参数、Duo Universal Prompt(OIDC)模式的会话存储机制、duoPing/duoAccountStatus/duoAdmin等 Actuator 端点,以及面向 curl/REST 等非浏览器环境的 Duo MFA 认证调用方式,并了解多 Duo 实例、用户注册、账号状态检查、密码无感认证(Passwordless)等进阶能力的实现原理。

1. Duo Security 与 CAS 集成概览

Duo Security 与 support/cas-server-support-duo-core 两个工程)。

Duo 为用户提供了多种认证方式:

  • 向智能手机推送通知,实现一键验证身份(需安装免费的 Duo Mobile 应用);
  • 由智能手机生成的一次性口令(one-time code);
  • 由 Duo 生成、通过短信发送到手机的一次性口令;
  • 由 Duo 拨打验证电话,引导用户确认登录请求。

从源码角度看,Duo 集成的主认证处理器 DuoSecurityAuthenticationHandler 实现了MultifactorAuthenticationHandler接口,并根据凭证类型分发到三种认证路径:DuoSecurityPasscodeCredential(一次性口令)、DuoSecurityUniversalPromptCredential(Universal Prompt OIDC 回调)、DuoSecurityDirectCredential(直接调用 Duo Auth API)。底层 HTTP 调用由 BaseDuoSecurityAuthenticationService 承载,其中AUTH_API_VERSION = 2表明与 Duo Auth API v2 交互,请求通过signRequest(integrationKey, secretKey)完成 HMAC 签名。

2. 核心配置:cas.authn.mfa.duo

启用该模块后,CAS 会通过cas.authn.mfa.duo配置块读取 Duo 连接信息。这些属性的绑定模型定义在 DuoSecurityMultifactorAuthenticationProperties 中,默认的 provider id 为mfa-duo(常量DEFAULT_IDENTIFIER)。

2.1 必填连接参数

以下三个参数是接入 Duo 的必需项,均标注了@RequiredProperty,并支持 Spring 表达式语言(@ExpressionLanguageCapable):

配置键说明
cas.authn.mfa.duo.duo-integration-keyDuo 集成密钥(Integration Key)。在 Duo Security 后台将 CAS 注册为受保护应用后获得
cas.authn.mfa.duo.duo-secret-keyDuo 密钥(Secret Key),与集成密钥配对使用
cas.authn.mfa.duo.duo-api-hostDuo API 主机地址(API hostname),同样在 Duo 后台获取

EqualsAndHashCode(of = {"duoApiHost", "duoIntegrationKey", "duoSecretKey"})表明这三个值共同决定一个 Duo 提供者实例的唯一性。在BaseDuoSecurityAuthenticationService中,这两个密钥会被注入signRequest()用于给每个请求签名,同时 CAS 与 Duo 的通信固定走 TCP 443 端口。

2.2 账号状态与属性收集

配置键默认值说明
cas.authn.mfa.duo.account-status-enabledtrue开启后 CAS 会在认证前调用 Duo 检查用户账号状态,判断用户是否具备从 Duo 侧进行 MFA 的资格。关闭则直接假定用户可以认证,不发起该 API 调用。账号状态检查要求 Duo 后台选择的集成类型具备足够的 API 权限;权限不足会导致 API 报错并写入日志,此时 CAS 会忽略账号状态继续认证流程
cas.authn.mfa.duo.collect-duo-attributestrue开启后,认证元数据与配置文件属性(如有)会从 Duo 收集为 CAS 属性
cas.authn.mfa.duo.principal-attribute空用于解析发送给 Duo 的用户名的主体属性,也用于校验 Duo 响应与令牌交换。未定义或找不到该属性时回退到默认 principal id。见 UniversalPromptDuoSecurityAuthenticationService#getDuoPrincipalId
cas.authn.mfa.duo.trusted-device-enabledfalse是否允许该提供者支持可信设备(Trusted Devices)

当collect-duo-attributes开启时,Universal Prompt 返回的 JWT(Token)会被展开为大量duo前缀属性,例如duoExp、duoIss、duoSub、duoPreferredUsername、duoAmr,认证结果相关属性duoAuthResult、duoAuthResultStatus,认证上下文相关属性duoAuthCtxFactor、duoAuthCtxReason、duoAuthCtxTxId,以及访问设备/认证设备的hostname、ip、location城市/国家/州等字段,具体逻辑见 UniversalPromptDuoSecurityAuthenticationService。

2.3 用户注册与 Admin API

配置键说明
cas.authn.mfa.duo.duo-admin-integration-keyDuo Admin 集成密钥,用于调用 Duo Admin API
cas.authn.mfa.duo.duo-admin-secret-keyDuo Admin 密钥
cas.authn.mfa.duo.registration.registration-url自建注册应用链接。若用户账号状态要求注册(enrollment)且配置了该链接,CAS 会把认证流程重定向到该注册应用;否则走 Duo 默认的新用户注册机制
cas.authn.mfa.duo.registration.crypto.*注册跳转 URL 中principal参数的 JWT 加密/签名配置。默认enabled=false,密钥尺寸见 DuoSecurityMultifactorAuthenticationRegistrationProperties

关于注册流程的更多细节,可参考 Duo Security 用户注册指南。

2.4 Bypass 跳过规则

cas.authn.mfa.duo配置块下的.bypass子配置用于定义哪些请求可以跳过 Duo MFA。CAS 的 MFA 跳过规则支持基于主体属性、认证属性、请求头、Cookie、IP 网段等条件进行匹配。若用户被判定为「直接绕过」(direct bypass),或用户尚未注册但新用户注册策略允许跳过注册,则 CAS 会直接绕过 Duo,并且不会向应用回传多因素认证上下文。相关测试可参考 DuoSecurityMultifactorProviderBypassConfiguration 对应的配置装配。

注意:Duo 官方近期出于安全原因调整了账号状态 API 的行为,可能不再精确返回账号状态。因此即使上述绕过条件成立,CAS 仍可能依据 API 返回的资格状态把用户路由到 Duo。具体行为以 Duo 官方 API 的演进为准。

3. Actuator 端点

该模块向 CAS 暴露了以下 Actuator 端点:

端点说明
duoPing按 provider id 探测 Duo Security 的连通性与可用性,返回每个提供者的duoApiHost、名称与availability
duoAccountStatus查询用户在 Duo 侧的账号状态
duoAdmin通过 Admin API 执行用户管理类操作
healthCAS 监控端点,用于汇总上报 Duo 健康状态

例如 DuoSecurityPingEndpoint 标注了@Endpoint(id = "duoPing", defaultAccess = Access.NONE),其pingDuo(String providerId)读取上下文中所有DuoSecurityMultifactorAuthenticationProvider,逐个调用底层duoService.ping()(Universal Prompt 模式下即 Duo 的healthCheck),并把结果以 JSON 形式返回。health端点的健康指示器为duoSecurityHealthIndicator,相关监控能力详见 CAS 监控端点文档。

4. 多 Duo 实例配置

CAS 的 Duo MFA 支持配置多个 Duo 提供者,每个提供者拥有独立的 id,可分别连接到不同的 Duo Security 实例并使用不同的配置。这一设计让敏感程度更高的应用可以连接到认证策略更严格、更安全的 Duo 实例。

实现要点:

  • 为每个 Duo 提供者分配一个自定义的唯一 id(例如mfa-duo-strict、mfa-duo-default);
  • 每个提供者实例都作为独立的 MFA provider 注册进 CAS,并按需在认证流程中被激活;
  • 若只有一个 Duo 实例,则无需定义 provider id(使用默认的mfa-duo)。

在认证处理器DuoSecurityAuthenticationHandler.supports()中,凭证的providerId会与当前 provider 的 id 进行匹配(multifactorAuthenticationProvider.getObject().matches(id)),从而实现不同应用路由到不同 Duo 实例。

5. 账号资料管理集成

Duo 集成能够向 CAS 的账号资料管理(Account Profile Management)功能提供用户设备注册信息,允许用户在个人中心查看和管理自己的 Duo 设备。其 Webflow 装配可参考 DuoSecurityMultifactorAccountProfileWebflowConfigurerTests。完整功能说明见 账号管理总览。

6. 健康状态检查

CAS 可按需联系 Duo Security,使用其pingAPI 查询服务健康状态。探测结果会记录并通过health端点(由 CAS 监控端点提供)上报。同时,Duo 认证流程中产生的相同结果也会被用来判定失败模式——即健康探测失败会直接影响认证流程的成败判断。

7. Universal Prompt(OIDC 模式)

7.1 原理与配置差异

Universal Prompt 是 Duo MFA 的一种变体,基于 Duo OIDC Auth API——一个符合 OIDC 标准的强双因素认证 API。与旧方案相比的关键变化:

  • 不再由 CAS 在 iframe 中托管 Duo Prompt:提示界面改为托管在 Duo 服务器上,通过浏览器重定向展示;
  • Duo 的响应通过浏览器重定向回传给 CAS,CAS 随后协商并兑换该响应,换取包含 MFA 用户资料详情的JWT(对应源码中的com.duosecurity.model.Token);
  • 不再需要生成和使用应用密钥(app key),取而代之的是client id与client secret。在 CAS 中,client id 与 client secret 即由duo-integration-key与duo-secret-key承担。将 CAS 注册为 Duo 受保护应用时,可从 Duo Security 后台获得集成密钥(integration key)、密钥(secret key)和 API 主机名(API hostname)。

在 UniversalPromptDuoSecurityAuthenticationService 中,authenticateInternal调用duoClient.getInstance().exchangeAuthorizationCodeFor2FAResult(code, principalId)完成授权码兑换,随后从 JWT 中提取preferred_username(为空则回退到sub)作为用户名,并按前文所述收集duo*属性。

7.2 会话存储(Session Storage)

在重定向到 Duo 之前,CAS 必须保留认证流程的状态,以便 Duo 重定向回来时恢复。该行为由cas.authn.mfa.duo.session-storage-type控制,取值定义在 SessionStorageTypes:

取值说明
BROWSER_STORAGE默认值。状态被签名并加密后交给浏览器存放在本地存储(local storage)。若本地存储不可用、被拦截或已满,CAS 回退到将同样的载荷以 Cookie 形式保存,按CasBrowserStorage_*分块命名,作用域为 CAS 上下文路径;Duo 响应处理完毕后这些 Cookie 会被立即清除。仅当浏览器既拒绝本地存储又拒绝 Cookie 时登录才失败
TICKET_REGISTRY状态保存在票据注册中心(ticket registry),以票据形式在集群内复制,完全不需要浏览器存储。注意:该取值自 7.3.0 起标记为@Deprecated,官方建议改用HTTP配合会话复制方案
HTTP会话数据保存在本地 HTTP servlet session 中。Duo 配置注释明确指出HTTP不适用于 Duo 流程

Cookie 体积警告:回退 Cookie 携带完整的认证流程状态,可能累积到数十 KB,在 Duo 响应处理完成前每次请求都会发送给 CAS。CAS 本身接受大体积请求头,但 CAS 前置的代理与负载均衡器默认常把请求头限制在 8 KB 或 16 KB,必须调整以允许更大的Cookie请求头。

8. 非浏览器环境 MFA

Duo 模块还支持非浏览器环境的多因素认证请求。触发方式:客户端(如curl、REST API 等)在请求中指定特殊的Content-Type,告知 CAS 该请求来自非 Web 环境。随后该 MFA 请求会以auto模式提交给 Duo Auth API,Duo 会推荐并转换为最适合用户设备的 out-of-band 因素(推送或电话)。

前置条件:CAS 还必须配置一种能支持非 Web 环境的主认证方式,例如 Basic Authentication。

以下curl示例先通过 Basic 认证进入某服务,同时把请求Content-Type标记为application/cas。假设该服务在 CAS 中配置了强制经过 Duo 的多因素策略:

curl --location --header "Content-Type: application/cas" https://apps.example.org/myapp -L -u casuser:Mellon

从源码看,Duo 的 Auth API 调用在 BaseDuoSecurityAuthenticationService 中完成,包含factor=auto的请求参数构造与 HMAC 签名。

9. REST 协议凭证提取

当启用了 CAS REST 协议 时,一个专门的凭证提取器会被注入 REST 认证引擎,用于识别 REST 请求中的 Duo 凭证并完成认证。装配逻辑见 DuoSecurityRestConfiguration:它注册DuoSecurityRestHttpRequestCredentialFactory(RestHttpRequestCredentialFactory实现),并仅在 Duo 认证服务条件满足时激活。

请求体中期望的参数名为passcode,该值可从 Duo Mobile 应用获取或通过短信收到。底层处理对应DuoSecurityPasscodeCredential路径:BaseDuoSecurityAuthenticationService.authenticateDuoPasscodeCredential()会构造带factor=passcode、passcode=...的 Auth API 请求并签名提交,Duo 返回result=allow时认证成功。

10. Passwordless(密码无感)认证

Duo 集成还可以充当 CAS Passwordless 认证 的账号存储(account store)。该行为必须在 CAS 设置中为符合条件的 MFA 提供者显式开启,即设置cas.authn.mfa.duo.passwordless-authentication-enabled=true。

需要澄清的是:此选项与 Duo Security 自身的 "Passwordless/PassKey" 能力无关,也与 CAS 的 WebAuthn/PassKey MFA 提供者无关,它只控制 CAS 直接提供的 Passwordless 认证特性。开启后:

  • CAS 会联系 Duo 查询符合条件的 Passwordless 账号;
  • 若账号已在 Duo 注册,CAS 切换为 Passwordless 流程,并利用用户注册的设备发送推送通知;
  • 要求用户已在 Duo 注册且具备有效的邮箱地址与手机设备;
  • 该功能要求 CAS 本身已具备 Passwordless 认证能力。

实现上,DuoSecurityPasswordlessUserAccountStore 实现了PasswordlessUserAccountStore:它遍历所有passwordlessAuthenticationEnabled=true的 Duo 提供者,通过 Admin API 查询用户账号(排除ENROLL状态),并映射为PasswordlessUserAccount(含用户名、邮箱、姓名、手机号与来源 provider id)。

11. 故障排查与日志

如需调试 Duo 集成,可在 log4j 配置文件中为 Duo 客户端 SDK 开启 debug 级别日志:

... <Logger name="com.duosecurity" level="debug" additivity="false"> <AppenderRef ref="casConsole"/> <AppenderRef ref="casFile"/> </Logger> ...

同时建议:

  • 使用NTP保证 CAS 服务器时间准确(HMAC 签名与 OIDC 令牌校验都依赖时间同步);
  • CAS 与 Duo 服务通信固定走TCP 443端口;
  • 不建议按目标 IP 地址或 IP 段配置出站防火墙规则,因为 Duo 官方为维持服务高可用会变更这些地址;应允许对 Duo 域名(通过 DNS 解析)的 443 出站访问。

12. 相关文档导航

  • Duo Security 用户注册指南
  • 账号管理总览
  • CAS 监控端点
  • Basic Authentication 配置
  • CAS REST 协议
  • Passwordless 认证(Duo 存储)
  • 后端
  • 认证鉴权
  • 单点登录

【免费下载链接】cas

Apereo CAS - Identity & Single Sign On for all earthlings and beyond.

项目地址:https://gitcode.com/gh_mirrors/ca/cas
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询