如何从WS-Federation返回的加密SAML 1断言中提取声明?
复用SAML 2.0声明提取代码处理WS-Fed的SAML 1.1断言
嘿,这个复用思路真的很赞——毕竟SAML 1.1和2.0的断言核心逻辑是相通的,完全没必要从头造轮子。我之前帮好几个团队搞定过AD FS下WS-Fed的声明提取问题,结合你提到的现有SAML 2.0代码,给你几个关键的调整方向:
1. 抽象命名空间适配层
首先要把现有代码里硬绑定的SAML 2.0命名空间解耦:
- SAML 2.0断言命名空间:
urn:oasis:names:tc:SAML:2.0:assertion - SAML 1.1断言命名空间:
urn:oasis:names:tc:SAML:1.0:assertion
你可以在解析入口加一个判断逻辑,通过断言根节点的xmlns属性自动识别所属版本,然后把XPath查询、DOM操作的规则切换到对应命名空间。这样核心的提取逻辑不用动,只需要改入口的适配部分。
2. 兼容声明结构的细微差异
虽然两者都用<AttributeStatement>和<Attribute>承载声明,但细节上有小区别:
- SAML 1.1的
<AttributeValue>通常没有NameFormat属性,就算有,格式值也和2.0不一样 - SAML 2.0支持更规范的
NameFormat枚举,比如urn:oasis:names:tc:SAML:2.0:attrname-format:uri
建议把声明提取逻辑封装成通用函数:先提取<Attribute>的Name作为声明类型,再遍历子节点<AttributeValue>获取值;对于NameFormat,如果是1.1版本没有这个属性,就用你系统内部的默认格式来兜底,不用强校验。
3. 处理WS-Fed的令牌包装结构
WS-Fed返回的响应不是直接的SAML断言,而是被包装在WS-Trust的结构里的:
- 如果是POST响应,你会拿到
wresult参数,里面是XML格式的<wst:RequestSecurityTokenResponse> - 先解析这个XML,找到
<wst:RequestedSecurityToken>节点,里面的内容就是SAML 1.1断言 - 把提取到的断言XML传给你已经通用化的解析函数就行
4. 签名与验证逻辑兼容
别漏掉签名验证的适配:
- SAML 1.1常用的签名算法偏旧,比如
http://www.w3.org/2000/09/xmldsig#rsa-sha1,要确保你的验证代码支持这些算法 <Conditions>节点的日期格式在1.1里可能更宽松,日期解析逻辑要做兼容,避免因为格式问题报错
伪代码示例
// 通用声明提取函数,兼容SAML 1.1/2.0 public Dictionary<string, List<string>> ExtractSamlClaims(XmlElement assertionElement) { var claims = new Dictionary<string, List<string>>(); var samlNs = assertionElement.NamespaceURI; // 根据命名空间构建XPath var xPath = samlNs == "urn:oasis:names:tc:SAML:2.0:assertion" ? "//saml2:AttributeStatement/saml2:Attribute" : "//saml1:AttributeStatement/saml1:Attribute"; var nsManager = new XmlNamespaceManager(assertionElement.OwnerDocument.NameTable); nsManager.AddNamespace("saml2", "urn:oasis:names:tc:SAML:2.0:assertion"); nsManager.AddNamespace("saml1", "urn:oasis:names:tc:SAML:1.0:assertion"); foreach (XmlNode attrNode in assertionElement.SelectNodes(xPath, nsManager)) { var claimType = attrNode.Attributes["Name"].Value; var values = attrNode.SelectNodes("./*[local-name()='AttributeValue']") .Cast<XmlNode>() .Select(n => n.InnerText) .ToList(); claims[claimType] = values; } return claims; } // 从WS-Fed响应中提取SAML 1.1断言 public XmlElement GetSaml11AssertionFromWsFed(string wsFedResponse) { var doc = new XmlDocument(); doc.LoadXml(wsFedResponse); var nsManager = new XmlNamespaceManager(doc.NameTable); nsManager.AddNamespace("wst", "http://schemas.xmlsoap.org/ws/2005/02/trust"); var tokenNode = doc.SelectSingleNode("//wst:RequestedSecurityToken/saml1:Assertion", nsManager); return tokenNode as XmlElement; }
避坑提醒
- AD FS返回的WS-Fed响应里,SAML断言可能是Base64编码的,一定要先解码再解析XML
- 如果是加密断言,解密逻辑可以复用现有SAML 2.0的代码,只要适配SAML 1.1的加密节点命名空间就行
这么调整之后,你现有SAML 2.0的大部分代码都能复用,只需要加一层适配层处理版本差异,成本很低的。
内容的提问来源于stack exchange,提问作者Eran
相关产品推荐
相关产品推荐

