微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用C#正确准备“HTTP重定向绑定”SAML请求

我需要使用HTTP重定向绑定方法创建SP启动的SAML 2.0身份验证事务.原来这很简单.只需获取IdP URI并连接一个查询字符串参数SAMLRequest. param是描述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,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));
    }
}

解决方法

我刚刚运行以下代码与您的示例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,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不被“调试器”站点接受.压缩是不可否认的,因为它可以正确地解压缩数据.它只是在算法中有一些区别,但是我不知道这个放气和放气的区别是什么?

原文地址:https://www.jb51.cc/csharp/97645.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐