Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/css/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Catch-22防止WIF保护的流式TCP WCF服务;毁了我的圣诞节精神健康_C#_Wcf_.net 4.5_Wif_Nettcpbinding - Fatal编程技术网

C# Catch-22防止WIF保护的流式TCP WCF服务;毁了我的圣诞节精神健康

C# Catch-22防止WIF保护的流式TCP WCF服务;毁了我的圣诞节精神健康,c#,wcf,.net-4.5,wif,nettcpbinding,C#,Wcf,.net 4.5,Wif,Nettcpbinding,我需要使用WIF保护流式WCF net.tcp服务端点。它应该根据令牌服务器对传入呼叫进行身份验证。该服务是流式的,因为它被设计用于传输大量数据 这似乎是不可能的。如果我不能避开捕获物,我的圣诞节就会毁了,我会在阴沟里喝得烂醉如泥,而快乐的购物者会踩在我慢慢冷却的身体上。伙计们,说真的 为什么这是不可能的?这是第二十二条军规 在客户机上,我需要使用从令牌服务器获取的信息创建一个通道。没问题 // people around here hate the Framework Design Guide

我需要使用WIF保护流式WCF net.tcp服务端点。它应该根据令牌服务器对传入呼叫进行身份验证。该服务是流式的,因为它被设计用于传输大量数据

这似乎是不可能的。如果我不能避开捕获物,我的圣诞节就会毁了,我会在阴沟里喝得烂醉如泥,而快乐的购物者会踩在我慢慢冷却的身体上。伙计们,说真的

为什么这是不可能的?这是第二十二条军规

在客户机上,我需要使用从令牌服务器获取的信息创建一个通道。没问题

// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();
我说“没问题”了吗?问题。事实上,
NullReferenceException
风格问题

“兄弟,”我问框架,“你有空检查吗?”框架没有声音,所以我拆开后发现

((IChannel)(object)tChannel).
    GetProperty<ChannelParameterCollection>().
    Add(federatedClientCredentialsParameter);
好极了。再也没有了。然而,现在我的客户在出生时就犯了错误(tho,我仍然爱他)。通过挖掘WCF诊断(protip:让你最坏的敌人在击溃他们并将他们赶在你前面,但在享受他们的妇女和孩子的哀叹之前这样做),我发现这是因为服务器和客户端之间的安全不匹配

“net”不支持请求的升级。tcp://localhost:49627/MyService'. 这可能是由于绑定不匹配(例如,在客户端而不是服务器上启用了安全性)

检查主持人的诊断(再次:粉碎、驾驶、阅读日志、享受哀悼),我发现这是真的

协议类型application/ssl tls已发送到不支持该类型升级的服务

“好吧,赛尔夫,”我说,“我会在主机上打开消息安全!”我做到了。如果您想知道它是什么样子,它是客户机配置的精确副本。抬头看

结果:Kaboom.

绑定('NetTcpBinding','')支持流式传输,而流式传输不能与消息级安全一起配置。考虑选择不同的传输模式或选择传输级安全性。 因此,我的主机不能通过令牌进行流式传输和安全保护。第二十二条军规


tl;dr:如何使用WIF保护流式net.tcp WCF端点?

WCF在流式传输的一些领域(我在看你,MTOM1)遇到了一个基本问题,即它如何无法按照大多数人认为的方式执行预验证(它只影响该频道的后续请求,而不是第一个请求)好的,所以这不完全是您的问题,但请继续,因为我将在最后讨论您的问题。通常HTTP质询的工作方式如下:

  • 客户端匿名访问服务器
  • 服务器说,对不起,401,我需要身份验证
  • 客户端使用身份验证令牌访问服务器
  • 服务器接受
  • 现在,如果您尝试在服务器上的WCF终结点上启用MTOM流,它不会抱怨。但是,当您在客户端代理上配置MTOM流时(您应该这样做,它们必须匹配绑定),它将爆炸性地死亡。原因是WCF试图阻止的上述事件序列如下:

  • 客户端在一次发布中以匿名方式将100MB的文件传输到服务器
  • 服务器说抱歉,401,我需要身份验证
  • 客户端再次使用身份验证头将100MB文件流式传输到服务器
  • 服务器接受
  • 请注意,当您只需要发送100MB时,您刚刚向服务器发送了200MB。这就是问题所在。答案是在第一次尝试时发送身份验证,但在WCF中,如果不编写自定义行为,这是不可能的。无论如何,我离题了

    你的问题

    首先,让我告诉你,你正在尝试的是不可能的。现在,为了让你停止转动轮子,让我告诉你为什么:

    我突然想到,您现在遇到了类似的问题。如果启用消息级安全性,客户端必须将整个数据流加载到内存中,然后才能使用ws-security所需的常用哈希函数和xml签名关闭消息。如果必须读取整个流以对单个消息进行签名,则ge(这不是真正的消息,但它是一个单一的连续流)然后您可以看到这里的问题。WCF必须在“本地”流一次以计算消息安全性,然后再次流一次以将其发送到服务器。这显然是一件愚蠢的事,因此WCF不允许流数据具有消息级安全性

    因此,这里的简单答案是,您应该将令牌作为参数发送到初始web服务,或者作为SOAP头发送,并使用自定义行为对其进行验证。您不能使用WS-Security来实现这一点。坦率地说,这不仅仅是一个WCF问题-我看不出它如何实际适用于任何其他堆栈

    解决MTOM问题

    这只是一个示例,我是如何解决基本身份验证的MTOM流问题的,因此,也许您可以大胆尝试,并为您的问题实现类似的功能。关键是为了启用自定义消息检查器,您必须禁用客户端代理上的所有安全概念(它在服务器上保持启用状态),但传输级别(SSL)除外:

    请注意,我已在此处关闭了传输安全性,因为我将使用消息检查器和自定义行为为自己提供:

    internal class BasicAuthenticationBehavior : IEndpointBehavior
    {
        private readonly string _username;
        private readonly string _password;
    
        public BasicAuthenticationBehavior(string username, string password)
        {
            this._username = username;
            this._password = password;
        }
        public void AddBindingParameters(ServiceEndpoint endpoint, 
            BindingParameterCollection bindingParameters) { }
        public void ApplyClientBehavior(ServiceEndpoint endpoint,
            ClientRuntime clientRuntime)
        {
            var inspector = new BasicAuthenticationInspector(
                this._username, this._password);
            clientRuntime.MessageInspectors.Add(inspector);
        }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
            EndpointDispatcher endpointDispatcher) { }
        public void Validate(ServiceEndpoint endpoint) { }
    }
    
    internal class BasicAuthenticationInspector : IClientMessageInspector
    {
        private readonly string _username;
        private readonly string _password;
    
        public BasicAuthenticationInspector(string username, string password)
        {
            this._username = username;
            this._password = password;
        }
    
        public void AfterReceiveReply(ref Message reply,
            object correlationState) { }
    
        public object BeforeSendRequest(ref Message request,
            IClientChannel channel)
        {
            // we add the headers manually rather than using credentials 
            // due to proxying issues, and with the 101-continue http verb 
            var authInfo = Convert.ToBase64String(
                Encoding.Default.GetBytes(this._username + ":" + this._password));
    
            var messageProperty = new HttpRequestMessageProperty();
            messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
            request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
    
            return null;
        }
    }
    
    因此,本示例适用于任何遭受MTOM问题困扰的人,但也可以作为实现类似于验证主要WIF安全令牌服务生成的令牌的框架

    希望这有帮助

    (一)


    (2) (请参阅“缺点”)

    好的,这里可能有一个无知的问题,但WIF真的需要消息模式吗?传输模式听起来像是w
    internal class BasicAuthenticationBehavior : IEndpointBehavior
    {
        private readonly string _username;
        private readonly string _password;
    
        public BasicAuthenticationBehavior(string username, string password)
        {
            this._username = username;
            this._password = password;
        }
        public void AddBindingParameters(ServiceEndpoint endpoint, 
            BindingParameterCollection bindingParameters) { }
        public void ApplyClientBehavior(ServiceEndpoint endpoint,
            ClientRuntime clientRuntime)
        {
            var inspector = new BasicAuthenticationInspector(
                this._username, this._password);
            clientRuntime.MessageInspectors.Add(inspector);
        }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
            EndpointDispatcher endpointDispatcher) { }
        public void Validate(ServiceEndpoint endpoint) { }
    }
    
    internal class BasicAuthenticationInspector : IClientMessageInspector
    {
        private readonly string _username;
        private readonly string _password;
    
        public BasicAuthenticationInspector(string username, string password)
        {
            this._username = username;
            this._password = password;
        }
    
        public void AfterReceiveReply(ref Message reply,
            object correlationState) { }
    
        public object BeforeSendRequest(ref Message request,
            IClientChannel channel)
        {
            // we add the headers manually rather than using credentials 
            // due to proxying issues, and with the 101-continue http verb 
            var authInfo = Convert.ToBase64String(
                Encoding.Default.GetBytes(this._username + ":" + this._password));
    
            var messageProperty = new HttpRequestMessageProperty();
            messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
            request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
    
            return null;
        }
    }