我需要使用 HTTP 重定向绑定方法创建一个 SP 发起的 SAML 2.0 身份验证事务。事实证明这很容易。只需获取 IdP URI 并连接一个查询字符串 param SAMLRequest
。参数是描述 SAML 请求的 xml 编码块。到现在为止还挺好。
将 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 调试器(它是一个有用的在线转换工具)来测试编码的输出。当我使用这个工具解码我的输出时,它就变成了无稽之谈。
因此,问题是:您知道如何将 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));
}
}