怎样正确准备的“HTTP重定向绑定”使用C#SAML请求 [英] How do I correctly prepare an 'HTTP Redirect Binding' SAML Request using C#

查看:675
本文介绍了怎样正确准备的“HTTP重定向绑定”使用C#SAML请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个SP使用HTTP重定向绑定方法发起SAML 2.0身份验证交易。原来,这是很容易的。刚刚获得国内流离失所者URI并连接一个单一的查询字符串参数 SAMLRequest 。该参数是XML的编码块,描述SAML请求。到目前为止好。



转换成SAML查询字符串参数时,问题就来了。我相信,准备的过程应该是:




  1. 构建一个SAML字符串

  2. 压缩此字符串

  3. 的Base64编码字符串

  4. URLEncode的字符串。



SAML请求

 < samlp:AuthnRequest 
的xmlns:samlp =金塔:绿洲:名称:TC:SAML:2.0:协议
的xmlns:SAML =瓮:绿洲:名称:TC:SAML:2.0:断言
ID ={0}
版=2.0
AssertionConsumerServiceIndex =0
AttributeConsumingServiceIndex =0>
< SAML:发行人> URN:XX-XX-XX< / SAML:发行人>
< samlp:NameIDPolicy
AllowCreate =真正的
格式=瓮:绿洲:名称:TC:SAML:2.0:NameID的格式:短暂/>
< / samlp:AuthnRequest>



代码



 私人字符串GetSAMLHttpRedirectUri(字符串idpUri)
{
VAR SAML =的String.Format(SAMLRequest,Guid.NewGuid());
VAR字节= Encoding.UTF8.GetBytes(SAML);使用(VAR输出=新的MemoryStream())
{
使用(VAR邮编=新DeflaterOutputStream(输出))
{
zip.Write(字节,0
,bytes.Length);
}
变种的base64 = Convert.ToBase64String(output.ToArray());
VAR进行urlencode = HttpUtility.UrlEncode的(Base64);
返回string.Concat(idpUri,SAMLRequest =?,进行urlencode);
}
}



我怀疑压缩不知何故惹的祸。我使用的 SharpZipLib DeflaterOutputStream 类,它应该?实现一个行业标准放气算法所以也许这里有一些设置我有错



该编码输出可以用这个的SAML2.0调试(它是一个有用的在线转换工具)。当我解码使用这个工具它出来胡说我的输出



因此​​,问题是:你知道如何将SAML字符串转换成正确的放气和编码SAMLRequest查询参数?



感谢您



修改1



接受的答案下面给出了答案的问题。这里是由所有后续的意见和答案修正的最终代码



编码SAMLRequest - 工作代码



 私人字符串GenerateSAMLRequestParam()
{
VAR SAML =的String.Format(SAMLRequest,Guid.NewGuid());
VAR字节= Encoding.UTF8.GetBytes(SAML);使用
(VAR输出=新的MemoryStream())
{
使用(VAR邮编=新DeflateStream(输出,CompressionMode.Compress))
{
zip.Write (字节,0,bytes.Length);
}
变种的base64 = Convert.ToBase64String(output.ToArray());
返回HttpUtility.UrlEncode的(Base64);
}
}



SAMLRequest 变量包含在这个问题的顶部显示的SAML。



解码SAMLResponse - 工作代码



 私人字符串DecodeSAMLResponse(字符串响应)
{
VAR UTF8 = Encoding.UTF8;
VAR字节= utf8.GetBytes(响应);使用
(VAR输出=新的MemoryStream())
{
使用(新DeflateStream(输出,CompressionMode.Decompress))
{
output.Write(字节, 0,bytes.Length);
}
变种的base64 = utf8.GetString(output.ToArray());
返回utf8.GetString(Convert.FromBase64String的(Base64));
}
}


解决方案

我刚刚打开你的榜样SAML运行下面的代码:

  VAR SAML =的String.Format(样品,Guid.NewGuid() ); 
VAR字节= Encoding.UTF8.GetBytes(SAML);

字符串中间;使用(VAR输出=新的MemoryStream())
{
使用(VAR邮编=新DeflaterOutputStream(输出))
zip.Write
(字节,0,bytes.Length) ;

中间= Convert.ToBase64String(output.ToArray());
}

字符串解码;使用
(VAR输入=新的MemoryStream(Convert.FromBase64String(中)))
使用(VAR解压=新的InflaterInputStream(输入))
使用(VAR读者=新的StreamReader(解压缩,编码.UTF8))
解码= reader.ReadToEnd();

布尔测试=解码== SAML;



测试变量是真正。这意味着,拉链/ BASE64 / unbase64 /解压缩正确执行往返。以后一定会出现错误。也许URLEncoder的破坏呢?你可以尝试类似的进行urlencode /解码测试?此外,检查结果是多长时间。它可能是所得到的URL,由于其长度截断



(编辑:我添加了一个StreamReader,而不是阅读,阵列早些时候我的示例使用的字节。 。。长度准备缓冲器和可能损坏测试立即读出从压缩流仅使用信息)



编辑

  VAR SAML =的String.Format(样品,Guid.NewGuid()); 
VAR字节= Encoding.UTF8.GetBytes(SAML);

字符串中间;
使用(VAR输出=新的MemoryStream())使用
{
(VAR邮编=新DeflateStream(输出,CompressionMode.Compress))
zip.Write(字节,0, bytes.Length);

中间= Convert.ToBase64String(output.ToArray());
}

//中间,应该是现在UrlEncode'd

字符串解码的事;使用
(VAR输入=新的MemoryStream(Convert.FromBase64String(中)))
使用(VAR解压=新DeflateStream(输入,CompressionMode.Decompress))
使用(VAR读者=新的StreamReader (解压缩,Encoding.UTF8))
解码= reader.ReadToEnd();

布尔测试=解码== SAML;



这段代码生成一个变量,即曾经是urlencoded进行,通过调试正常通过。 DeflateStream 来自标准.NET的 System.IO.Compression 命名空间。我没有,为什么SharpZip的放气不是由调试现场接受了丝毫的想法。不可否认的是,压缩工作,因为它设法妥善解压缩数据..它只是要在算法差一些,但我不能告诉是这个放气和放气,德哦之间的区别。


I need to create an SP initiated SAML 2.0 Authentication transaction using HTTP Redirect Binding method. It turns out this is quite easy. Just get the IdP URI and concatenate a single query-string param SAMLRequest. The param is an encoded block of xml that describes the SAML request. So far so good.

The problem comes when converting the SAML into the query string param. I believe this process of preparation should be:

  1. Build a SAML string
  2. Compress this string
  3. Base64 encode the string
  4. UrlEncode the string.

The SAML Request

<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>

The Code

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);
    }
}

I suspect the compression is somehow to blame. I am using the DeflaterOutputStream class from SharpZipLib which is supposed to implement an industry standard deflate-algorithm so perhaps there are some settings here I have wrong?

The encoded output can be tested using this SAML2.0 Debugger (its a useful online conversion tool). When I decode my output using this tool it comes out as nonsense.

The question therefore is: Do you know how to convert a SAML string into the correctly deflated and encoded SAMLRequest query-param?

Thank you

EDIT 1

The accepted answer below gives the answer to the problem. Here is final code as corrected by all subsequent comments and answers.

Encode SAMLRequest - Working Code

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);
    }
}

The SAMLRequest variable contains the SAML shown at the top of this question.

Decode SAMLResponse - Working Code

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));
    }
}

解决方案

I've just run the following code with your example SAML:

        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, 0, 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;

The test variable is true. This means that the zip/base64/unbase64/unzip roundtrip performs correctly. The error must occur later. Maybe the URLEncoder destroys them? Could you try similar urlencode/decode test? Also, check how long the result is. It may be possible that the resulting URL is truncated due to its length.

(edit: I've added a StreamReader instead of reading to arrays. Earlier my sample used bytes.Length to prepare the buffer and that could damage the test. Now the reading uses only the information from the compressed stream)

edit:

        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, 0, 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;

this code produces a middle variable, that once is UrlEncoded, passes through the debugger properly. DeflateStream comes from the standard .Net's System.IO.Compression namespace. I don't have the slightest idea why the SharpZip's Deflate is not accepted by the 'debugger' site. It is undeniable that the compression works, as it manages to decompress the data properly.. it just has to be some difference in the algorithms, but I cannot tell what is the difference between this deflate and that deflate, d'oh.

这篇关于怎样正确准备的“HTTP重定向绑定”使用C#SAML请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆