将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,bytes.Length); } var base64 = Convert.ToBase64String(output.ToArray()); var urlEncode = HttpUtility.UrlEncode(base64); return string.Concat(idpUri,"?SAMLRequest=",urlEncode); } }
我怀疑压缩是不知何故的.我正在使用SharpZipLib中的DeflaterOutputStream类,它应该实现行业标准的deflate-algorithm,所以也许这里有一些设置我错了?
编码输出可以使用此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,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,bytes.Length); } var base64 = utf8.GetString(output.ToArray()); return utf8.GetString(Convert.FromBase64String(base64)); } }
解决方法
var saml = string.Format(sample,Guid.NewGuid()); var bytes = Encoding.UTF8.GetBytes(saml); string middle; using (var output = new MemoryStream()) { using (var zip = new DeflaterOutputStream(output)) zip.Write(bytes,bytes.Length); middle = Convert.ToBase64String(output.ToArray()); } string decoded; using (var input = new MemoryStream(Convert.FromBase64String(middle))) using (var unzip = new InflaterInputStream(input)) using (var reader = new StreamReader(unzip,Encoding.UTF8)) decoded = reader.ReadToEnd(); bool test = decoded == saml;
测试变量是true.这意味着zip / base64 / unbase64 /解压缩往返执行正常.错误必须在以后出现.也许URLEncoder破坏他们?你可以尝试类似的urlencode /解码测试吗?另外,检查结果是多久.生成的URL可能由于其长度而被截断.
(编辑:我已经添加了一个StreamReader而不是读数组.早期我的示例使用bytes.Length来准备缓冲区,并且可能会损坏测试现在阅读仅使用来自压缩流的信息)
编辑:
var saml = string.Format(sample,Guid.NewGuid()); var bytes = Encoding.UTF8.GetBytes(saml); string middle; using (var output = new MemoryStream()) { using (var zip = new DeflateStream(output,CompressionMode.Compress)) zip.Write(bytes,bytes.Length); middle = Convert.ToBase64String(output.ToArray()); } // MIDDLE is the thing that should be now UrlEncode'd string decoded; using (var input = new MemoryStream(Convert.FromBase64String(middle))) using (var unzip = new DeflateStream(input,CompressionMode.Decompress)) using (var reader = new StreamReader(unzip,Encoding.UTF8)) decoded = reader.ReadToEnd(); bool test = decoded == saml;
此代码生成一个中间变量,一次是UrlEncoded,正确地通过调试器. DeflateStream来自标准的.Net的System.IO.Compression命名空间.我没有丝毫的想法为什么SharpZip的Deflate不被“调试器”站点接受.压缩是不可否认的,因为它可以正确地解压缩数据.它只是在算法中有一些区别,但是我不知道这个放气和放气的区别是什么?