7.8 KiB
CAS 2.0/3.0 接入指南
本文说明如何把一个 CAS Provider Instance 接入 SkillHub 统一身份核心。CAS 登录默认关闭, 配置不完整或 Authority 状态异常时不会出现在登录方法目录中。
1. 前置条件
-
SkillHub 的公开入口和 CAS Server 使用 HTTPS。
-
Redis 可用。CAS state 使用 Redis 原子消费,以支持多 Pod 和重放保护。
-
CAS Server 已允许下面的精确 Service URL:
https://<skillhub-host>/api/v1/auth/cas/<provider-code>/callback -
已确认可作为稳定身份键的 CAS principal 或 immutable attribute。
provider-code 和 authority 是持久身份绑定的一部分。产生 Identity Binding 后不能通过
普通配置变更切换到另一个身份域。
2. 配置
| 环境变量 | 必填 | 默认值 | 说明 |
|---|---|---|---|
SKILLHUB_AUTH_CAS_ENABLED |
是 | false |
显式启用 CAS |
SKILLHUB_AUTH_CAS_PROVIDER_CODE |
是 | cas |
Provider Instance code,需长期稳定 |
SKILLHUB_AUTH_CAS_DISPLAY_NAME |
是 | CAS |
登录页展示名 |
SKILLHUB_AUTH_CAS_AUTHORITY |
是 | 空 | 稳定 CAS 身份域 ID |
SKILLHUB_AUTH_CAS_SERVER_URL |
是 | 空 | CAS Server 根地址,例如 https://cas.example.com/cas |
SKILLHUB_AUTH_CAS_SERVICE_URL |
是 | 空 | 精确 SkillHub callback,不含 query/fragment |
SKILLHUB_AUTH_CAS_PROTOCOL_VERSION |
是 | 3.0 |
2.0 或 3.0 |
SKILLHUB_AUTH_CAS_SUBJECT_TYPE |
是 | cas_principal |
统一身份核心中的 Subject type |
SKILLHUB_AUTH_CAS_ATTRIBUTES_SUBJECT |
否 | 空 | 为空时使用 CAS principal;否则使用唯一 immutable attribute |
SKILLHUB_AUTH_CAS_ATTRIBUTES_DISPLAY_NAME |
否 | 空 | display name attribute |
SKILLHUB_AUTH_CAS_ATTRIBUTES_EMAIL |
否 | 空 | email attribute,固定按 asserted 处理 |
SKILLHUB_AUTH_CAS_ATTRIBUTES_AVATAR_URL |
否 | 空 | avatar URL attribute |
SKILLHUB_AUTH_CAS_CONNECT_TIMEOUT |
否 | PT5S |
连接超时 |
SKILLHUB_AUTH_CAS_READ_TIMEOUT |
否 | PT10S |
请求总超时 |
SKILLHUB_AUTH_CAS_STATE_TTL |
否 | PT5M |
登录 state 有效期,最大 15 分钟 |
SKILLHUB_AUTH_CAS_MAX_RESPONSE_BYTES |
否 | 1048576 |
validation 响应上限,1 KiB–1 MiB |
CAS 返回的普通 email attribute 不是 verified email,不能用于
EMAIL_DOMAIN 准入或静默账号绑定。
Docker Compose
编辑 .env.release:
SKILLHUB_AUTH_CAS_ENABLED=true
SKILLHUB_AUTH_CAS_PROVIDER_CODE=cas-main
SKILLHUB_AUTH_CAS_DISPLAY_NAME=Corporate CAS
SKILLHUB_AUTH_CAS_AUTHORITY=corp-cas
SKILLHUB_AUTH_CAS_SERVER_URL=https://cas.example.com/cas
SKILLHUB_AUTH_CAS_SERVICE_URL=https://skills.example.com/api/v1/auth/cas/cas-main/callback
SKILLHUB_AUTH_CAS_PROTOCOL_VERSION=3.0
SKILLHUB_AUTH_CAS_SUBJECT_TYPE=cas_principal
SKILLHUB_AUTH_CAS_ATTRIBUTES_DISPLAY_NAME=displayName
SKILLHUB_AUTH_CAS_ATTRIBUTES_EMAIL=mail
启动前运行:
./scripts/validate-release-config.sh .env.release
Helm
auth:
cas:
enabled: true
providerCode: cas-main
displayName: Corporate CAS
authority: corp-cas
serverUrl: https://cas.example.com/cas
serviceUrl: https://skills.example.com/api/v1/auth/cas/cas-main/callback
protocolVersion: "3.0"
subjectType: cas_principal
connectTimeout: PT5S
readTimeout: PT10S
stateTtl: PT5M
maxResponseBytes: 1048576
attributes:
subject: ""
displayName: displayName
email: mail
avatarUrl: ""
Chart 在渲染阶段拒绝 HTTP endpoint、缺失 URL 和 provider code 不匹配的 callback。
Kustomize
修改 deploy/k8s/base/configmap.yaml 中的 auth-cas-* 字段,然后重新应用 overlay。
CAS 配置不包含 client secret;若企业扩展引入凭证,必须放入 Kubernetes Secret,不能放
在 ConfigMap。
3. 身份映射
默认映射:
primary subject = CAS principal
subject type = cas_principal
email assurance = PROVIDER_ASSERTED
aliases = none
如果 CAS principal 可能随用户名变更,必须配置
SKILLHUB_AUTH_CAS_ATTRIBUTES_SUBJECT 指向 CAS Server 明确定义且实际返回的 immutable
attribute,并为该属性选择稳定的 subject-type。属性缺失、多值或空值时登录 fail closed。
不要把 email、display name 或临时用户名当作稳定 Subject。
4. 验证
-
匿名请求登录方法目录:
curl -fsS 'https://skills.example.com/api/v1/auth/methods'只在 Provider 为
READY时应出现CAS_REDIRECT。 -
在浏览器点击 CAS 登录,确认重定向到 CAS
/login,其service解码后与配置的 callback 加一次性state完全一致。 -
完成 CAS 登录,确认返回原始
returnTo或默认页面,并能请求/api/v1/auth/me。 -
再次请求相同 callback,必须得到
casInvalidState或 CAS Ticket 验证失败,不能建立 第二个 Session。 -
检查应用日志中不包含
ST-Ticket、validation URL、上游完整响应或用户属性。 -
禁用 Provider 后,方法目录不再显示 CAS,且点击旧 URL 不应连接 CAS Server。
-
在账号安全页验证 CAS Identity Link:已绑定 CAS 可以完成 fresh reauthentication, READY intent 可以通过目标 CAS 创建 Binding;失败后应回到同一 intent,成功后不能重放。
建议分别验证 CAS 2 XML、CAS 3 JSON、CAS 3 XML fallback、无效 Ticket、错误 Service、 超时、TLS 失败、XXE、超大响应和 Redis 不可用。
CAS callback 按协议会在 query string 中携带一次性 ticket 和 state。官方 Web
镜像不记录 query string 或 Referer,应用请求日志会对它们进行隐藏;如果前面还有
Ingress、负载均衡、WAF、APM 或其他反向代理,必须将该 callback 路径的 query string
和 Referer 关闭记录或至少对 ticket、state 脱敏。上线前应使用唯一测试 Ticket
检查完整日志链路,确认没有原文残留。重复 state 会分类为 REPLAY_DETECTED 并写入
不含 state/Ticket 的安全审计。
5. 升级与回滚
- 新配置默认关闭,不影响现有本地密码、GitHub、GitLab 或 OIDC 登录。
- 本次接入不修改
PlatformPrincipal或现有 Session 序列化结构。 - 旧版本回滚后会忽略 CAS 环境变量;现有非 CAS 登录仍可使用。
- CAS 已产生 Binding 后回滚会暂时失去 CAS 登录入口,但不会删除账号、Binding 或业务 数据。
- 修改 CAS endpoint 可以保持同一 Authority;修改 Authority 必须走统一身份设计中的 显式 Authority 迁移流程。
6. 安全实现说明
实现阶段验证了 Spring Security CAS 所依赖的 Apereo Java CAS Client。其 4.1.1
AbstractUrlBasedTicketValidator 仍会在 DEBUG 记录包含 Ticket 的 validation URL 和完整
响应;CAS 2 自定义属性解析路径也没有满足本项目要求的全部 XML parser fail-closed
设置。因此当前实现没有调用该库的 URL validator,而是使用受限 JDK HTTP transport 和
严格 parser:
- 禁止 redirect;
- 明确连接、请求和响应大小上限;
- XML 禁止 DOCTYPE、外部实体、外部 DTD 和外部 schema;
- Ticket、完整响应和属性不写日志或异常;
- CAS 3 优先 JSON,并支持受限 XML fallback。
上游参考:
如果上游版本修复这些问题,可以在保持错误分类、响应上限和无敏感日志测试的前提下重新 评估替换 transport/parser。