本地 Mock OAuth2/OIDC 提供方(mock-oidc.py)¶
位置:
deploy/nfos/tools/mock-oidc.py| 语言:python3 | 是否需要 root:否
工具性质:本地测试替身(常驻 HTTP 服务,只写内存/终端,不写文件)
运行前提:无需仓库检出;全部配置走环境变量,无命令行参数
部署状态:随仓库检出运行,不部署到 /opt/Cy/services/system.d/nfos/;绝不可当作线上认证端点
用途¶
在本地拉起一个 Mock OAuth 2.0 / OIDC 提供方,用于验证 nfarmsd 的 OAuth 客户端链路(discovery → authorize → token → userinfo)。
源码 docstring 给出的定位(逐字引用):
Local mock OAuth 2.0 / OIDC provider for verifying the nfarmsd OAuth client chain.
Documentation addresses only (RFC 5737): bound to 127.0.0.1, endpoints advertised
as http://203.0.113.10:8088/... but the client is configured to talk to
http://127.0.0.1:8088 (both are "documentation/loopback" and allowed by the
`allow_insecure_endpoints` switch).
实现的端点(源码 docstring 逐字):
Endpoints:
GET /.well-known/openid-configuration discovery (optional capability)
GET /authorize?... issues ?code=&state= (PKCE S256 checked)
POST /token form OR json, checks PKCE + redirect_uri
GET /userinfo Bearer -> JSON identity
关键行为:
| 环节 | 源码行为 |
|---|---|
/authorize |
生成随机 code-...,把 code_challenge / code_challenge_method / redirect_uri / client_id 记在内存 CODES,302 回 ?code=&state= |
/token 编码 |
支持 application/x-www-form-urlencoded 与 application/json;其它 Content-Type → 415;MOCK_REQUIRE_FORM=1 时 JSON 也被 415 拒绝 |
/token 校验顺序 |
场景开关(idp_error/http500)先于 code 校验;code → client_id → client_secret → redirect_uri → PKCE S256;全部通过后才 pop 授权码(避免把“第一次失败”误报成“码不存在”) |
/token 成功 |
返回 access_token(u-...)、expires_in、refresh_token、token_type、scope |
/userinfo |
读 Authorization: Bearer,命中内存 TOKENS 返回身份;未命中返回 {"code": 20005, ...} |
PUT |
405;其它路径 404 |
本页不复述源码内的
MOCK_CLIENT_SECRET默认字面值(它只是一个文档占位值,非真实凭据,但为避免被明文机密扫描器计入“可疑点”而略去);以源码为准,实际联调时请用环境变量显式覆盖。
典型场景¶
- 联调 nfarmsd 的 OAuth 客户端:本地起 mock,验证 discovery 能力探测、授权码换 token、PKCE S256、
redirect_uri严格匹配; - 制造故障场景:
MOCK_TOKEN_MODE=idp_error验证客户端对invalid_grant的分类与告警文案,MOCK_TOKEN_MODE=http500验证 5xx 重试/降级; - 验证客户端对非标准编码的容忍度:
MOCK_REQUIRE_FORM=1(走标准 OIDC 行为,只收 form)对比默认(form/json 都收); - 验证
/userinfo身份字段映射:用MOCK_USER_JSON换一份身份返回。
用法与参数¶
本工具不接受命令行参数(无 argparse、不读 sys.argv),全部开关通过环境变量。源码 docstring 的开关说明(逐字引用):
Scenario knobs (env):
MOCK_USER_JSON JSON object returned by /userinfo for the happy path
MOCK_TOKEN_MODE ok | idp_error | http500
MOCK_REQUIRE_FORM 1 -> reject json token requests with 415 (standard-OIDC behaviour)
完整参数表(键名、默认值逐字来自源码的 os.environ.get(...)):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
MOCK_ISSUER |
字符串(URL) | http://203.0.113.10:8088 |
discovery 里广播的 issuer 及三个 endpoint 前缀(文档地址段) |
MOCK_BIND |
字符串(地址) | 127.0.0.1 |
监听地址(只绑回环) |
MOCK_PORT |
整数 | 8088 |
监听端口(非特权端口,无需 root) |
MOCK_CLIENT_ID |
字符串 | cli_mock_docvalue_0001 |
/token 校验用的 client_id |
MOCK_CLIENT_SECRET |
字符串 | (源码内文档占位值,本页不复述) | /token 校验用的 client_secret;非真实凭据 |
MOCK_REDIRECT_URI |
字符串(URL) | http://127.0.0.1:9989/auth/oauth/callback |
/authorize 未带 redirect_uri 时的兜底回调 |
MOCK_TOKEN_MODE |
枚举 ok | idp_error | http500 |
ok |
/token 场景开关:正常 / 400 invalid_grant / 500 |
MOCK_REQUIRE_FORM |
字符串开关(1 才生效) |
0 |
1 → 拒绝 JSON 形式的 /token(返回 415) |
MOCK_USER_JSON |
JSON 对象 | null → 内置 DEFAULT_USER |
/userinfo happy path 返回的身份;解析结果为空时回落内置示例用户 |
无参数时的默认行为:以上全部取默认值 —— 在 127.0.0.1:8088 起常驻服务,token_mode=ok、require_form=0、/userinfo 返回内置文档示例用户。
示例¶
起服务(前台常驻):
stderr 会打印一行启动信息(源码逐字格式):
另开一个终端验证 discovery:
故障场景(PowerShell 设环境变量后启动):
| 情形 | 退出码语义 |
|---|---|
| 正常前台常驻 | 无常驻退出码约定(服务不自行退出) |
| 手动终止(Ctrl+C) | 无自检语义;不输出 PASS/FAIL 结论 |
| 端口被占用 / 绑定失败 | 异常退出(Python traceback,非自检语义) |
配置值非法(如 MOCK_PORT 非整数) |
模块加载期 ValueError(Python traceback) |
依赖与权限¶
- 语言/版本:Python 3(
#!/usr/bin/env python3)。 - 第三方依赖:无,标准库
base64/hashlib/json/os/sys/time/urllib.parse/http.server。 - 仓库依赖:无。
- 权限:不需要 root(8088 非特权端口,且只绑
127.0.0.1)。不需要写权限。
风险与注意事项¶
- 纯离线、不写盘:状态全在内存(
CODES/TOKENS/LOG),进程一退出即全部丢失;不写任何文件、不访问外网(只作为服务端被本地客户端访问)。 - 这是测试替身,不是 IdP:
/authorize不做真实用户认证,/token的 client_secret 校验对象是源码内的文档占位值。严禁把本服务暴露到非回环地址或用于任何真实认证场景;MOCK_BIND改成对外地址等于开放一个“谁都能换到 token”的端点。 - 默认配置里
CLIENT_SECRET是文档占位值 —— 若用真实口令去覆盖环境变量做联调,注意不要把口令写进命令行历史/脚本;本页与源码均不记录任何真实口令。 MOCK_BIND默认回环、ISSUER广播的是文档地址段(203.0.113.0/24,RFC 5737),二者不一致是有意设计:客户端被配置为访问127.0.0.1:8088,并由allow_insecure_endpoints开关放行。- 守护进程性质:前台常驻会占用端口;Windows 下若端口被占需先释放或改
MOCK_PORT。
回滚¶
本工具不部署到线上、不改线上系统,也不产出任何文件:
- 无输出文件、无临时目录、无日志落盘(访问日志只进内存
LOG列表,未在响应中输出); - 停止方式:
Ctrl+C结束前台进程即可,进程退出后内存状态(授权码、token)自然失效; - 无需清理文件系统;若曾用环境变量覆盖过终端会话,关闭该终端或清除对应变量即可。