第二十二条军规禁止 WIF 安全的流式 TCP WCF 服务; 破坏我的圣诞节,心理健康

我对 使用 WIF 保护流式 WCF net.tcp 服务端点有要求。它应该可以验证来自我们令牌服务器的呼叫。该服务是流式的,因为它的设计目的是传输大量的数据 n 东西。

这似乎是不可能的。如果我不能绕过这个陷阱,我的圣诞节就毁了,我会在阴沟里喝死自己,而快乐的购物者们会踏过我慢慢变冷的身体。我是认真的,伙计们。

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

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

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

是异常的来源,并且 GetProperty调用返回的是 null。那么,卧槽?结果是,如果我打开 Message security 并将客户端凭据类型设置为 IssuedToken,那么这个属性现在存在于 ClientFactory中(提示: 在 IChannel 中没有“ SetProperty”等价物,这个混蛋)。

<binding name="OMGWTFLOL22" transferMode="Streamed" >
<security mode="Message">
<message clientCredentialType="IssuedToken"/>
</security>
</binding>

太好了。不再有 NRE 了。然而,现在我的客户是 出生时就有缺陷(仍然爱他,虽然)。通过深入研究 WCF 的诊断(提示: 让你最大的敌人在粉碎他们并在你面前驾驶他们之后这样做,但在享受他们的妇女和儿童的哀悼之前) ,我发现这是因为服务器和客户端之间的安全不匹配。

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

查看主持人的对话框(同样是: 碾压,驾驶,阅读日志,享受悲叹) ,我发现这是真的

Protocol Type application/ssl-tls 被发送到不支持该类型升级的服务。

“那么,self,”我说,“我只需要打开主机上的消息安全性!”

结果: 砰。

绑定(‘ NetTcpBinding’,‘ http://tempuri.org/’)支持不能与消息级安全一起配置的流。考虑选择不同的传输模式或选择传输级别的安全性。

我的主机不能同时通过令牌进行流传输和保护第22条军规。

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

5808 次浏览

WCF 在流媒体的一些领域有些问题(我看着你,MTOM1) ,因为它不能像大多数人认为的那样执行预认证(它只会影响对该频道的后续请求,而不是第一个请求)好的,所以这不是你的问题,但请跟着我,我会在最后解决你的问题。通常 HTTP 挑战的工作原理是这样的:

  1. 客户端匿名访问服务器
  2. 服务器说,对不起,401,我需要认证
  3. 客户端使用身份验证令牌访问服务器
  4. 服务器接受。

现在,如果您尝试在服务器上的 WCF 端点上启用 MTOM 流,它将不会抱怨。但是,当您在客户机代理上配置它时(正如您应该做的那样,它们必须匹配绑定) ,它会爆炸性地死亡。之所以出现这种情况,是因为周转基金试图防止的上述一系列事件如下:

  1. 客户端在一个 POST 中匿名地将100MB 文件传输到服务器
  2. 服务器说抱歉401我需要认证
  3. 客户端再次流100MB 的文件到一个认证头服务器
  4. 服务器接受。

注意,当您只需要发送100MB 时,您刚刚向服务器发送了200MB。这就是问题所在。答案是在第一次尝试时发送身份验证,但是如果不编写自定义行为,在 WCF 中这是不可能的。总之,我跑题了。

你的问题

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

我突然想到,你现在也陷入了类似的问题。如果启用消息级安全性,客户机必须将整个数据流加载到内存中,然后才能使用 ws-security 所需的通常散列函数和 xml 签名实际关闭消息。如果它必须读取整个流来对单个消息进行签名(实际上这不是一个消息,而是一个连续的单个流) ,那么您可以在这里看到问题。WCF 必须在“本地”流一次以计算消息安全性,然后再流一次以将其发送到服务器。这显然是一件愚蠢的事情,因此 WCF 不允许流数据的消息级安全性。

因此,这里的简单答案是,您应该将令牌作为参数发送给初始 Web 服务,或者作为 SOAP 头发送,并使用自定义行为来验证它。不能使用 WS-Security 进行此操作。坦率地说,这不仅仅是周转基金的问题-我看不出它如何能够实际工作在任何其他堆栈。

解决 MTOM 问题

这只是我如何解决基本身份验证的 MTOM 流问题的一个示例,因此也许您可以利用这一点,为您的问题实现类似的东西。关键在于,为了启用自定义消息检查器,除了传输级别(SSL)之外,还必须禁用客户机代理上的所有安全性概念(在服务器上仍然启用) :

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

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

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 中的消息安全(见“缺点”)