Ошибка проверки подписи 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));

Я получаю правду за все выше, кроме двух последних. Так:

  1. SAML действителен
  2. SAML имеет действительную подпись
  3. Сертификат открытого ключа в SAML совпадает с файлом сертификата, который у нас есть
  4. 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.

Другие вопросы по тегам