SAML签名验证失败

时间:2013-10-19 09:09:01

标签: salesforce x509certificate saml-2.0 component-space

我们的IdP是Salesforce.com组织。 SP是第三方.Net应用程序。在开发过程中,第三方报告说他们无法验证发送的SAML响应。

我们决定尝试使用ComponentSpace验证SAML响应。以下是我们的尝试:

// Load the certificate from the file: certInFile
// Load the SAML in an XMLElement: samlXml
// Retrieve the certificate from the SAML: certInSaml

Console.WriteLine("SAML is valid ? " + SAMLResponse.IsValid(samlXml));
Console.WriteLine("Is SAML signed? " + SAMLMessageSignature.IsSigned(samlXml));
Console.WriteLine("Certificate found in SAML is same as certificate file? " + certInFile.Equals(certInSaml));
Console.WriteLine("Validated SAML with certificate found in SAML" + SAMLMessageSignature.Verify(samlXml, certInSaml));
Console.WriteLine("Validated SAML with certificate file" + SAMLMessageSignature.Verify(samlXml, certInFile));

除了最后两个,我对上述所有事情都是如此。所以:

  1. SAML有效
  2. SAML具有有效签名
  3. SAML中的公钥证书与我们的证书文件相同
  4. SAML使用证书文件或SAML中发送的公钥的私钥进行签名
  5. 从3,4我们可以得出结论,Salesforce正在签署但是使用不同的证书但在响应中发送了错误的公钥吗?!

    修改:示例SAML在此http://pastebin.com/J8FTxnhJ

    我错过了什么?

3 个答案:

答案 0 :(得分:4)

XML签名验证失败,因为签名后修改了XML或者使用了错误的证书来验证签名。最可能的情况是使用了错误的证书。

Salesforce使用其私钥对SAML响应进行签名。使用Salesforce管理控制台,您可以下载应该用于执行签名验证的相应公钥/证书。

调用SAMLMessageSignature.Verify时,您可以指定用于执行验证的X509Certificate,这通常是您应该做的。

但是,base-64编码的X.509证书也嵌入在XML签名中。您可以使用此嵌入式证书来检查签名是否验证。

为此,请勿将X509证书传递给SAMLMessageSignature.Verify

例如:SAMLMessageSignature.Verify(samlXml, null);

如果有效但指定证书失效,则确认使用了错误的证书。

您可以调用SAMLMessageSignature.GetCertificate从XML签名中检索X.509证书,以将其与正在使用的证书进行比较。

另外,作为旁注,XML签名适用于XML。无法使用HTTP Post数据中发送的base-64编码的SAML响应直接验证它们。在尝试验证XML签名之前,必须将后期数据解码为XML。

答案 1 :(得分:1)

当我们没有解码生成的base64编码的SAML但直接尝试验证它时,这是有效的。但是,仍然不确定为什么ComponentSpace方法报告的解码字符串不同。

答案 2 :(得分:0)

我知道这是一篇过时的文章,但是我遇到了同样的问题,并对未回答感到不满意。对于那些正在遇到此问题并通过Internet搜索找到此页面作为使用ComponentSpace进行Salesforce SAML签名验证失败的唯一结果之一的人,该问题可能不在SAML签名验证本身内,而是您如何解码base-64编码的SAML响应有效负载。

请注意,采用SAMLServiceProvider.ReceiveSSO()的{​​{1}}方法不会遇到此问题。我发现这是在手动解码可能触发此问题的有效负载时,具体取决于IdP签名响应时XML的格式

由于这是一篇较旧的文章,并且pastebin链接已不复存在,因此我们假设原始代码可能如下所示。 (还假设X.509证书已嵌入有效负载中,但最终的解决方法是相同的。)

HttpRequest

对于Salesforce(可能还有其他),xcert将为非null,isSigned和isValid设置为true,但是isVerified将为false。上面的代码简单,难以捉摸吗? var str = Encoding.UTF8.GetString(Convert.FromBase64String(samlResponse)); XmlDocument xdoc = new XmlDocument(); xdoc.LoadXml(str); var xcert = SAMLMessageSignature.GetCertificate(xdoc.DocumentElement); var isSigned = SAMLMessageSignature.IsSigned(xdoc.DocumentElement); var isValid = SAMLResponse.IsValid(xdoc.DocumentElement); var isVerified = SAMLMessageSignature.Verify(xdoc.DocumentElement);

原因是因为签名是基于原始XML结构(或其某些子节)生成的。如果IdP在其原始SAML XML中包含空格,则即使在XML中通常可以忽略空格,也将其包括在签名生成中。这就是为什么签名验证失败时IsValid仍返回true的原因。

最后一个方便的注释被埋在ComponentSpace的示例代码中,完整的 safe XmlDocument转换是:

xdoc.PreserveWhitespace = true;

对于我们的情况,我们不需要在使用XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore; xmlReaderSettings.XmlResolver = null; XmlDocument xmlDocument = new XmlDocument(); xmlDocument.PreserveWhitespace = true; xmlDocument.XmlResolver = null; using (XmlReader xmlReader = XmlReader.Create(new StreamReader(fileName), xmlReaderSettings)) { xmlDocument.Load(xmlReader); } 的额外步骤中包含DtdProcessing.Ignore,而是将其包含在此解决方案中以涵盖所有用例。