首页
/ SAML Azure AD 联合身份 API 参考:从联邦元数据到 Graph API 配置的实战指南

SAML Azure AD 联合身份 API 参考:从联邦元数据到 Graph API 配置的实战指南

2026-09-09 21:16:42作者:郦嵘贵Just

导读

本文以 Anthropic-Cybersecurity-Skills 仓库中 skills/building-identity-federation-with-saml-azure-ad/references/api-reference.md 为核心,系统梳理基于 SAML 2.0 构建 Microsoft Entra ID(原 Azure AD)联合身份时涉及的全部关键 API 端点、元数据字段、XML 命名空间与绑定 URI,并结合仓库中的 SKILL.mdworkflows.mdstandards.md 及可运行的验证脚本 agent.pyprocess.py 展开源码级解读。读完本文,你将掌握联合元数据的拉取与解析方法、SAML 端点的正确配置方式、SP 元数据必备字段、Graph API 应用注册姿势,以及一套可直接落地的配置校验清单。

一、联合身份背景与 API 参考的定位

在企业混合身份架构中,SAML 2.0 联合使本地 Active Directory(通过 AD FS 或第三方 IdP)认证过的用户能够无缝访问云端资源,而无需在云端维护一套独立凭据。仓库中 SKILL.md 明确指出:联合身份消除了密码同步的顾虑,将认证权威保留在本地,同时将 SSO 扩展到云资源。

该技能共提供四种联合模型,决定着你调用哪些 API、配置哪些端点:

模型 认证权威 典型场景
联合(AD FS) 本地 AD FS 法规要求认证留在本地
托管(PHS) Azure AD + 密码哈希同步 最简单的云认证,无需 AD FS
托管(PTA) 本地传递认证代理 云认证回本地 AD 校验
第三方联合 外部 IdP(Okta、Ping 等) 多 IdP 环境

api-reference.md 正是这套架构下与微软云侧交互的"接线图":无论是拉取 IdP 联合元数据、解析 SP 元数据,还是通过 Graph API 注册应用、执行配置校验,都围绕本文的端点与字段展开。仓库中的 agent.py 将这张接线图完整落地为可执行代码,后续章节会逐一对应。

二、联合元数据 URL:一切配置的起点

联合元数据(Federation Metadata)是一个描述 IdP 端点与能力的 XML 文档,是 IdP 与 SP 双方建立信任的"名片"。

https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-06/federationmetadata.xml

其中 {tenant-id} 是 Azure AD 租户的全局唯一标识(GUID)。在 agent.py 中,该 URL 被直接用于拉取租户的 SAML 联合元数据:

def fetch_federation_metadata(tenant_id):
    """Fetch Azure AD SAML federation metadata."""
    url = f"https://login.microsoftonline.com/{tenant_id}/federationmetadata/2007-06/federationmetadata.xml"
    resp = requests.get(url, timeout=15)
    resp.raise_for_status()
    logger.info("Fetched federation metadata for tenant %s", tenant_id)
    return resp.text

值得注意的实现细节:

  • 超时控制timeout=15 防止网络故障导致脚本无限挂起;
  • 异常传播raise_for_status() 会在返回非 2xx 状态码(如租户不存在、网络被阻断)时立即抛出异常,避免对无效元数据做无意义的后续解析;
  • 同样的元数据端点约定也被用在 AD FS 侧——SKILL.md 中配置 Relying Party Trust 时使用的 https://nexus.microsoftonline-p.com/federationmetadata/2007-06/federationmetadata.xml 正是微软在线身份平台的元数据地址。

从元数据文档中,可以解析出 IdP 的 entityID、所有 SingleSignOnService 端点及其绑定方式、以及令牌签名证书。这些解析逻辑对应 agent.py

def parse_metadata(xml_text):
    """Parse SAML federation metadata XML."""
    ns = {"md": "urn:oasis:names:tc:SAML:2.0:metadata", "ds": "http://www.w3.org/2000/09/xmldsig#"}
    root = ET.fromstring(xml_text)
    idp_desc = root.find(".//md:IDPSSODescriptor", ns)
    sso_services = []
    if idp_desc is not None:
        for sso in idp_desc.findall("md:SingleSignOnService", ns):
            sso_services.append({"binding": sso.get("Binding"), "location": sso.get("Location")})
    certs = []
    for cert_elem in root.findall(".//ds:X509Certificate", ns):
        if cert_elem.text:
            certs.append(cert_elem.text.strip()[:100] + "...")
    entity_id = root.get("entityID", "")
    return {"entity_id": entity_id, "sso_services": sso_services, "certificates": certs}

这段代码的价值在于:元数据解析是整个联合配置自动化中风险最高的环节——命名空间写错、XPath 路径不对都会静默返回空结果,进而导致校验误判。因此 agent.py 专门将"元数据中没有 SSO 服务"和"元数据中没有签名证书"都判为 critical 级别问题。

三、SAML 2.0 端点一览

联合配置中,Azure AD 作为 IdP 向 SP 暴露三类核心端点,三者共用同一个路径:

端点 URL
SSO(POST) https://login.microsoftonline.com/{tenant}/saml2
SSO(Redirect) https://login.microsoftonline.com/{tenant}/saml2
Logout https://login.microsoftonline.com/{tenant}/saml2

{tenant} 可以是租户 ID(GUID),也可以是已验证的自定义域名(如 corp.example.com)。从 agent.py 可以看到,客户端在解析出 SSO 服务列表后,会分别检查 HTTP-RedirectHTTP-POST 两种绑定是否可用,其中 HTTP-POST 缺失被记为 medium 严重级别——因为 HTTP-POST 是绝大多数 SAML SP 首选的断言接收方式。

需要强调的一点:同一 URL 承载多种绑定/功能,意味着联合配置中对端点的区分不靠 URL 路径,而靠协议栈中的 Binding 属性与消息类型(AuthnRequestResponseLogoutRequest)来判定。这也是为什么下文 XML 命名空间与绑定 URI 的精确性如此关键——在 process.py 中,AD FS 元数据校验正是依赖命名空间精确匹配 md:IDPSSODescriptor 下的 ds:X509Certificate 节点来统计证书数量。

四、SP 元数据必备字段

当你的应用作为服务提供商(SP)接入 Azure AD 联合时,需要对外发布 SP 元数据,其中四个字段是必备的:

字段 说明
entityID SP 唯一标识符(全局唯一,不能与任何其他 SP 冲突)
AssertionConsumerService ACS URL(POST 绑定),SAML 断言的回传地址
NameIDFormat emailAddresspersistent
SingleLogoutService SLO URL(可选,但建议配置)

agent.pygenerate_sp_metadata() 函数完整复现了这一字段结构:

def generate_sp_metadata(entity_id, acs_url, slo_url=None):
    """Generate Service Provider SAML metadata."""
    metadata = {
        "entityID": entity_id,
        "assertionConsumerService": {"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", "location": acs_url},
        "nameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
    }
    if slo_url:
        metadata["singleLogoutService"] = {"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", "location": slo_url}
    return metadata

实现细节中值得注意的两点:

  1. 默认 nameIDFormatemailAddress(即 urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress)。这与 SKILL.md 中 SaaS 应用配置步骤"NameID: user.userprincipalname(email 格式)"的约定一致;
  2. SLO 绑定与 ACS 绑定不同:ACS 使用 HTTP-POST 回传断言,而 SLO 使用 HTTP-Redirect 跳转。这是 SAML 常见的最佳实践组合——主动发送用 POST 保证断言完整性,登出跳转用 Redirect 保持简洁。

当 NameID 需要稳定的账号锚点时,应改用 persistent 格式。在 SKILL.md 的 AD FS 声明规则中,正是将 UPN 作为 persistent 格式的 NameID 透传(urn:oasis:names:tc:SAML:2.0:nameid-format:persistent),确保 Azure AD 能够通过稳定的标识符关联到已同步的用户对象。

五、XML 命名空间:解析元数据的钥匙

解析 SAML 元数据与断言时,必须正确声明以下命名空间前缀。 api-reference.md 给出了 Python 解析的命名空间字典:

ns = {
    "md": "urn:oasis:names:tc:SAML:2.0:metadata",
    "ds": "http://www.w3.org/2000/09/xmldsig#",
    "saml": "urn:oasis:names:tc:SAML:2.0:assertion",
}
前缀 命名空间 URI 用途
md urn:oasis:names:tc:SAML:2.0:metadata 元数据文档结构(EntityDescriptorIDPSSODescriptorSingleSignOnService 等)
ds http://www.w3.org/2000/09/xmldsig# XML 数字签名(X509Certificate 等证书节点)
saml urn:oasis:names:tc:SAML:2.0:assertion SAML 断言结构(AssertionSubjectAttributeStatement 等)

仓库两个脚本各自印证了这些命名空间的使用方式:

  • agent.pymd + ds 解析 Azure AD 元数据中的 SSO 服务与证书;
  • process.py 用同样的前缀组合定位 AD FS 元数据中的 IDPSSODescriptor/KeyDescriptor/KeyInfo/X509Data/X509Certificate 节点。

一个常见的坑:命名空间前缀名称可以随意(md/md1/m 均可),但 URI 必须逐字符精确匹配。如果 URI 拼写错误或缺失,findall 将返回空列表,导致"元数据看起来正常但解析结果为空"的隐性故障。这也是 process.py 捕获 Exception 并返回 parse_error 的原因——把解析异常显性暴露出来,而不是静默吞掉。

六、SAML 绑定 URI 速查

SAML 2.0 定义了多种消息传输绑定,每种绑定有标准的命名空间 URI,在元数据与端点配置中必须按此精确填写:

绑定 URI
HTTP-POST urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
HTTP-Redirect urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
SOAP urn:oasis:names:tc:SAML:2.0:bindings:SOAP

此外,standards.md 还提到 SAML 2.0 存在 HTTP Artifact 绑定,但 Azure AD 联合场景中最常使用的是前两种。

在实战中的典型用法:

  • SP 元数据中的 ACS:声明为 HTTP-POST 绑定(见上文 generate_sp_metadata),表示 SP 期望以 POST 方式接收 SAML Response;
  • SLO 端点:声明为 HTTP-Redirect 绑定;
  • 校验逻辑agent.py 在解析 IdP 元数据后,检查 sso_services 中是否存在 HTTP-POSTHTTP-Redirect 绑定,以此判断 IdP 的能力是否满足 SP 的需求——这是将绑定 URI 用于程序化校验的直接证据。

七、Azure AD Graph API:应用注册与联合配置

除了元数据层面的交互,联合配置还涉及 Microsoft Graph API 的调用。 api-reference.md 给出了创建服务主体的示例:

POST https://graph.microsoft.com/v1.0/servicePrincipals
Authorization: Bearer TOKEN
{
  "appId": "app-id",
  "preferredSingleSignOnMode": "saml",
  "loginUrl": "https://app.example.com/login"
}

关键字段含义:

字段 说明
appId 已注册应用(App Registration)的应用程序 ID
preferredSingleSignOnMode 设为 saml 表明该服务主体使用 SAML SSO 模式
loginUrl 应用的登录 URL,用于 IdP 发起的 SSO 流程

在仓库中,Graph API 的调用被 process.pyFederationAuditor 类系统化落地。其认证与调用链路包括:

  1. MSAL 客户端凭据获取令牌process.py):使用 msal.ConfidentialClientApplication 以客户端 ID + 客户端密钥换取 https://graph.microsoft.com/.default 作用域下的访问令牌;
  2. 域列表查询process.py):GET /v1.0/domains,提取每个域的 authenticationTypeFederated / Managed 等)、验证状态与是否默认域;
  3. 联合配置查询process.py):GET /v1.0/domains/{domain_id}/federationConfiguration,返回 issuerUripassiveSignInUrisigningCertificate 等关键配置;404 时返回 None(表示该域不是联合域);
  4. 登录日志审计process.py):GET /v1.0/auditLogs/signIns?$filter=userPrincipalName endswith '{domain}',用于验证联合用户的真实登录行为。

运行审计器所需的最小 Graph 权限如下(process.py):

- Domain.Read.All
- AuditLog.Read.All
- Directory.Read.All

依赖安装与使用方式:

pip install msal requests cryptography
auditor = FederationAuditor(tenant_id, client_id, client_secret)
report = auditor.generate_federation_audit_report()
print(json.dumps(report, indent=2))

审计报告会为每个联合域输出 issuer_urisign_in_urlcertificate_health(含 days_until_expiryneeds_renewal 标记),并将证书过期(Critical)与 30 天内到期(High)写入 findings 列表——这正对应 api-reference.md 校验清单中"Certificate present"为 Critical 级别的实践。证书到期检测通过 check_certificate_expiry 对 Base64 编码的证书做 DER 解码后读取 not_valid_after_utc 实现。

八、配置校验清单:严重级别与实操对照

api-reference.md 定义的四项校验,在仓库脚本中均有对应实现,并叠加了 SKILL.md 验证清单中的安全项:

校验项 严重级别 代码实现
ACS URL 使用 HTTPS High agent.py#L61-L62:检查 assertionConsumerService.location 是否以 https:// 开头
证书存在 Critical agent.py#L59-L60:IdP 元数据中无证书判 Critical;process.py 进一步校验到期时间
HTTP-POST 绑定可用 Medium agent.py#L63-L66:遍历 SSO 服务绑定判断
NameID 格式已配置 Medium agent.py#L47:SP 元数据中显式声明 nameIDFormat

执行入口为 agent.py 的 main()

python agent.py --tenant-id <TENANT_ID> --sp-entity-id <SP_ENTITY_ID> --acs-url <ACS_URL> [--slo-url <SLO_URL>] [--output saml_report.json]

完整参数说明:

参数 必填 说明
--tenant-id Azure AD 租户 ID
--sp-entity-id 服务提供方实体 ID
--acs-url Assertion Consumer Service URL
--slo-url Single Logout URL
--output 报告输出路径,默认 saml_report.json

执行后会拉取租户元数据 → 生成 SP 元数据 → 执行校验 → 输出 JSON 报告,报告包含 idp_metadatasp_configurationvalidation 三个区块,并以 SAML REPORT: VALID/INVALID, N findings 的形式打印摘要。

从源码结构看validate_configuration 的判定逻辑是:只要不存在 critical 级别问题即判定 valid,但 High/Medium 问题仍会完整记录在 findings 中——这意味着"校验通过"不代表"配置完美",实施时应把 High/Medium 项也逐一关闭。这一设计与 SKILL.md 验证清单相互呼应:证书自动轮换、智能锁定、外网锁定策略、AD FS 健康与证书到期监控、托管认证回退方案等,都属于联合上线前的安全加固闭环。

九、故障场景:联合中断时的 API 侧处置

结合 workflows.md 的故障切换工作流,联合架构遇到 AD FS 中断时,API 侧的处置路径与本文端点/校验体系直接相关:

  1. 状态判定:通过 process.pyvalidate_adfs_metadata 探测 AD FS 元数据端点是否可达,获取 entity_idcertificate_countmetadata_size 作为健康证据;
  2. 回退方案 A(暂态切换):启用密码哈希同步作为备份,利用 Azure AD 分阶段发布(staged rollout)将部分用户组切到托管认证;
  3. 回退方案 B(紧急转换):执行 Convert-MgDomainToManaged(对应 PUT /v1.0/domains/{domainId}/federationConfiguration 类操作的反向),将所有用户切至 Azure AD 直接认证;
  4. 恢复验证:AD FS 恢复后重建联合信任,重新将域转回 federated,并通过 process.py 的登录日志接口确认 authenticationProtocol 已回到联合认证路径。

证书轮换同样是 API 侧的常见操作:自动轮换模式下,AD FS 在证书到期前 20 天生成新证书并作为辅助证书加入,Azure AD 通过元数据刷新自动获取(workflows.md);手动轮换则需依次执行 Set-AdfsCertificate(添加为辅助)→ Update-MgDomainFederationConfiguration 更新 Azure AD → 等待 24-48 小时复制 → 提升为主证书 → 移除旧证书。整个轮换窗口的健康状态都可以用 process.pygenerate_federation_audit_report() 持续监控。

十、速查与合规映射

最后,将 API 参考中所有关键值汇总为速查表,便于实际配置时对照使用:

对象 关键值
元数据 URL https://login.microsoftonline.com/{tenant-id}/federationmetadata/2007-06/federationmetadata.xml
SSO/Logout 端点 https://login.microsoftonline.com/{tenant}/saml2
元数据命名空间 urn:oasis:names:tc:SAML:2.0:metadata
签名命名空间 http://www.w3.org/2000/09/xmldsig#
断言命名空间 urn:oasis:names:tc:SAML:2.0:assertion
HTTP-POST 绑定 urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
HTTP-Redirect 绑定 urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
SOAP 绑定 urn:oasis:names:tc:SAML:2.0:bindings:SOAP
emailAddress NameID urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
persistent NameID urn:oasis:names:tc:SAML:2.0:nameid-format:persistent

在合规层面,standards.md 给出了本架构对应的合规映射:

  • NIST SP 800-63C:FAL1(Bearer 断言直接呈现)、FAL2(Bearer 断言附加安全)、FAL3(持有者密钥断言);
  • FedRAMP:IA-2/IA-5/IA-8,跨组织访问要求联合;
  • ISO 27001:2022:A.5.16 身份管理、A.5.17 认证信息、A.8.5 安全认证。

这意味着上述 API 端点与校验项不仅是工程配置,也是满足审计要求的可验证证据——建议在实施完成后,将 agent.py 的校验报告与 process.py 的审计报告一并归档,形成配置基线。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
397
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525