Ошибка проверки подписи SAML
Наш 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));
Я получаю правду за все выше, кроме двух последних. Так:
- SAML действителен
- SAML имеет действительную подпись
- Сертификат открытого ключа в SAML совпадает с файлом сертификата, который у нас есть
- SAML подписывается закрытым ключом ни файла сертификата, ни открытым ключом, отправленным в SAML
Из 3,4 мы можем сделать вывод, что Salesforce подписывает, но с другим сертификатом, но отправляет неправильный открытый ключ в ответе?!
Редактировать: образец SAML здесь http://pastebin.com/J8FTxnhJ
Что мне не хватает?
2 ответа
Это работало, когда мы не декодировали сгенерированный SAML в кодировке base64, а пытались его проверить напрямую. Однако до сих пор не уверен, почему методы ComponentSpace по-разному сообщают для декодированной строки.
Я знаю, что это старый пост, но я столкнулся с той же проблемой и был недоволен отсутствием ответа. Для тех, кто столкнулся с этой проблемой и нашел эту страницу в поиске в Интернете как один из единственных результатов неудачной проверки подписи SAML Salesforce с использованием ComponentSpace, проблема, скорее всего, не в самой проверке подписи SAML, а в том, как вы декодирование полезной нагрузки ответа SAML в кодировке base-64.
Обратите внимание, что SAMLServiceProvider.ReceiveSSO()
метод, который требует HttpRequest
не страдает этой проблемой. Я обнаружил, что эту проблему может вызвать именно ручное декодирование полезной нагрузки, в зависимости от формата XML, когда IdP подписал ответ.
Поскольку это более старый пост и ссылка на pastebin давно исчезла, предположим, что исходный код мог выглядеть следующим образом. (Также предполагается, что сертификат X.509 встроен в полезную нагрузку, но исправление в конечном итоге такое же.)
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);
В случае Salesforce (и, вероятно, других) xcert будет отличным от нуля, для isSigned и isValid будет установлено значение true, а для isVerified будет false. Простое и неуловимое исправление вышеуказанного кода?xdoc.PreserveWhitespace = true;
Причина в том, что подпись создается на основе необработанной структуры XML (или некоторого ее подраздела). Если IdP имеет пробелы в исходном SAML XML, он включается в генерацию подписи, даже если пробелы обычно можно игнорировать в XML. Вот почему IsValid по-прежнему будет возвращать значение true, хотя проверка подписи завершится ошибкой.
И последнее удобное примечание, скрытое в образце кода ComponentSpace, полное безопасное преобразование XmlDocument:
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
на дополнительном этапе использования XmlReaderSettings
, но включив его в это решение, чтобы охватить все варианты использования.
Сбой проверки подписи XML либо потому, что XML был изменен после подписания, либо для проверки подписи используется неправильный сертификат. Наиболее вероятный сценарий - использование неверного сертификата.
Salesforce подписывает ответ SAML, используя свой закрытый ключ. Используя консоль администратора Salesforce, вы можете загрузить соответствующий открытый ключ / сертификат, который следует использовать для проверки подписи.
При звонке SAMLMessageSignature.Verify
, вы можете указать X509Certificate
использовать для выполнения проверки, которая, как правило, то, что вы должны сделать.
Однако сертификат X.509 в кодировке Base-64 также встроен в подпись XML. Вы можете использовать этот встроенный сертификат, чтобы проверить, проверяет ли подпись.
Для этого не передавайте сертификат X509 SAMLMessageSignature.Verify
,
Например: SAMLMessageSignature.Verify(samlXml, null);
Если это работает, но указание сертификата не работает, это подтверждает, что используется неправильный сертификат.
Ты можешь позвонить SAMLMessageSignature.GetCertificate
извлечь сертификат X.509 из подписи XML и сравнить его с используемым сертификатом.
Также, как примечание, подписи XML применяются к XML. Их нельзя проверить напрямую, используя ответ SAML в кодировке base-64, отправленный в данных HTTP Post. Данные поста должны быть декодированы в XML перед попыткой проверки подписи XML.