Мне нужно создать инициированную SP транзакцию аутентификации SAML 2.0 с использованием метода переадресации HTTP-переадресации. Оказывается, это довольно легко. Просто получите IdP URI и объедините один параметр строки запроса SAMLRequest
. Параметр является закодированным блоком xml, который описывает запрос SAML. Пока все хорошо.
Проблема возникает при преобразовании SAML в параметр строки запроса. Я считаю, что этот процесс подготовки должен быть:
- Построить строку SAML
- Сжатие этой строки
- Base64 кодирует строку
- UrlEncode строка.
Запрос SAML
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="{0}"
Version="2.0"
AssertionConsumerServiceIndex="0"
AttributeConsumingServiceIndex="0">
<saml:Issuer>URN:xx-xx-xx</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
Код
private string GetSAMLHttpRedirectUri(string idpUri)
{
var saml = string.Format(SAMLRequest, Guid.NewGuid());
var bytes = Encoding.UTF8.GetBytes(saml);
using (var output = new MemoryStream())
{
using (var zip = new DeflaterOutputStream(output))
{
zip.Write(bytes, 0, bytes.Length);
}
var base64 = Convert.ToBase64String(output.ToArray());
var urlEncode = HttpUtility.UrlEncode(base64);
return string.Concat(idpUri, "?SAMLRequest=", urlEncode);
}
}
Я подозреваю, что сжатие как-то виновато. Я использую класс DeflaterOutputStream
из SharpZipLib, который должен реализовывать стандартный алгоритм дефлята, поэтому, возможно, здесь есть некоторые настройки. я ошибаетесь?
Закодированный вывод может быть протестирован с помощью этого SAML2.0 Debugger (его полезный инструмент онлайн-конвертации). Когда я декодирую свой вывод с помощью этого инструмента, он выглядит как бессмыслица.
Таким образом, возникает вопрос: знаете ли вы, как преобразовать строку SAML в правильно дефлированный и закодированный запрос-параметр SAMLRequest?
Спасибо
РЕДАКТИРОВАТЬ 1
Принятый ниже ответ дает ответ на проблему. Вот окончательный код, исправленный всеми последующими комментариями и ответами.
Кодировать SAMLRequest - Рабочий код
private string GenerateSAMLRequestParam()
{
var saml = string.Format(SAMLRequest, Guid.NewGuid());
var bytes = Encoding.UTF8.GetBytes(saml);
using (var output = new MemoryStream())
{
using (var zip = new DeflateStream(output, CompressionMode.Compress))
{
zip.Write(bytes, 0, bytes.Length);
}
var base64 = Convert.ToBase64String(output.ToArray());
return HttpUtility.UrlEncode(base64);
}
}
Переменная SAMLRequest
содержит SAML, показанный в верхней части этого вопроса.
Декодировать SAMLResponse - Рабочий код
private string DecodeSAMLResponse(string response)
{
var utf8 = Encoding.UTF8;
var bytes = utf8.GetBytes(response);
using (var output = new MemoryStream())
{
using (new DeflateStream(output, CompressionMode.Decompress))
{
output.Write(bytes, 0, bytes.Length);
}
var base64 = utf8.GetString(output.ToArray());
return utf8.GetString(Convert.FromBase64String(base64));
}
}