Catch-22 prevents streamed TCP WCF service securable by WIF; ruining my Christmas, mental health
我需要使用wif保护流式wcf net.tcp服务端点。它应该针对我们的令牌服务器对传入的呼叫进行身份验证。这项服务之所以被流化,是因为它的设计目的是传输大量的数据。
这似乎是不可能的。如果我不能避开这个陷阱,我的圣诞节将被毁掉,我会在阴沟里喝死自己,而快乐的购物者会跨过我慢慢冷却的身体。我是认真的,伙计们。
为什么这是不可能的?这是22号门。
在客户机上,我需要使用从令牌服务器获取的genericXMLSecurityToken创建一个通道。没问题。
1 2 3 4 | // people around here hate the Framework Design Guidelines. var token = Authentication.Current._Token; var service = base.ChannelFactory.CreateChannelWithIssuedToken(token); return service.Derp(); |
我说"没问题"了吗?问题。实际上,
"兄弟,"我问框架,"你连空检查都没有吗?"框架是无声的,所以我拆开发现
1 2 3 | ((IChannel)(object)tChannel). GetProperty<ChannelParameterCollection>(). Add(federatedClientCredentialsParameter); |
是异常的来源,
1 2 3 4 5 | <binding name="OMGWTFLOL22" transferMode="Streamed"> <security mode="Message"> <message clientCredentialType="IssuedToken"/> </security> </binding> |
甜的。没有更多的NRIs。然而,现在我的客户在出生时就有过错(仍然爱他,透)。通过对WCF诊断的深入研究(Protip:让你最坏的敌人在碾碎他们并在你面前驾驶他们之后,但在享受他们妇女和孩子的哀悼之前),我发现这是因为服务器和客户机之间的安全不匹配。
The requested upgrade is not supported by 'net.tcp://localhost:49627/MyService'. This could be due to mismatched bindings (for example security enabled on the client and not on the server).
检查主机的诊断(再次:挤压、驾驶、阅读日志、享受悲伤),我发现这是真的。
Protocol Type application/ssl-tls was sent to a service that does not support that type of upgrade.
"好吧,我自己,"我说,"我就打开主机上的消息安全!"我也是。如果您想知道它是什么样子的,它是客户机配置的精确副本。抬头看,
结果:Kaboom。
The binding ('NetTcpBinding','http://tempuri.org/') supports streaming which cannot be configured together with message level security. Consider choosing a different transfer mode or choosing the transport level security.
因此,我的主机不能同时通过令牌进行流式传输和安全保护。第二十二条军规。
tl;dr:如何使用wif保护流式net.tcp wcf端点????
WCF在流媒体的一些领域(我在看你,MTOM1),由于一个基本问题,即它如何不能像大多数人认为的那样执行预身份验证(它只影响对该频道的后续请求,而不是第一个请求),所以这不是你的问题,但请按照我将得到的来做到最后你的。通常,HTTP质询的工作方式如下:
现在,如果您尝试在服务器上的WCF端点上启用MTOM流,它将不会抱怨。但是,当您在客户机代理服务器上配置它时(正如您应该配置的那样,它们必须匹配绑定),它将在激烈的死亡中爆炸。原因是WCF试图阻止的上述事件序列是:
注意,当只需要发送100MB时,您刚刚向服务器发送了200MB。这就是问题所在。答案是在第一次尝试时发送身份验证,但如果不编写自定义行为,在WCF中是不可能的。不管怎样,我离题了。
你的问题
首先,让我告诉你你正在尝试的是不可能的。现在,为了让你停止转动你的轮子,让我告诉你为什么:
我突然想到,你现在正徘徊在一个类似的问题中。如果启用消息级安全性,则客户端必须先将整个数据流加载到内存中,然后才能使用WS-Security所需的常规哈希函数和XML签名实际关闭消息。如果它必须读取整个流来签署单个消息(这不是真正的消息,但它是一个连续的流),那么您可以在这里看到问题。WCF必须在"本地"流一次以计算消息安全性,然后再次流一次以将其发送到服务器。这显然是一个愚蠢的事情,所以WCF不允许流数据的消息级安全性。
因此,这里的简单答案是,您应该将令牌作为参数发送到初始Web服务,或者作为SOAP头发送,并使用自定义行为来验证它。不能使用WS-Security执行此操作。坦率地说,这不仅仅是一个WCF问题——我看不出它实际上如何适用于任何其他堆栈。
解决MTOM问题
这只是一个示例,我如何解决基本身份验证的MTOM流问题,所以也许您可以利用这一点,为您的问题实现类似的东西。其关键在于,为了启用自定义消息检查器,除了传输级别(SSL)之外,必须禁用客户端代理上的所有安全概念(它在服务器上保持启用状态):
1 2 3 4 5 6 7 8 | this._contentService.Endpoint.Behaviors.Add( new BasicAuthenticationBehavior( username: this.Settings.HttpUser, password: this.Settings.HttpPass)); var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding; binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; // Do not provide |
请注意,我已经关闭了这里的传输安全性,因为我将使用消息检查器和自定义行为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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安全令牌服务生成的令牌的框架。
希望这有帮助。
(1)大数据流
(2)WCF中的消息安全性(参见"缺点")。