我在这里遇到一种奇怪的情况。我搞定了,但我不明白为什么。 情况如下:
我的应用程序(网站)必须调用WCF服务。 WCF服务公开netTcpBinding并需要传输安全性(Windows)。 客户端和服务器位于同一个域中,但位于不同的服务器上 因此,生成客户端会导致以下配置(主要是默认值)
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="MyTcpEndpoint" ...>
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:xxxxx/xxxx/xxx/1.0"
binding="netTcpBinding" bindingConfiguration="MyTcpEndpoint"
contract="Service.IMyService" name="TcpEndpoint"/>
</client>
</system.serviceModel>
当我运行网站并拨打该服务时,我收到以下错误:
System.ServiceModel.Security.SecurityNegotiationException: Either the target name is incorrect or the server has rejected the client credentials. ---> System.Security.Authentication.InvalidCredentialException: Either the target name is incorrect or the server has rejected the client credentials. ---> System.ComponentModel.Win32Exception: The logon attempt failed
--- End of inner exception stack trace ---
at System.Net.Security.NegoState.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.NegotiateStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.InitiateUpgradeAsyncResult.OnCompleteAuthenticateAsClient(IAsyncResult result)
at System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorAsyncResult.CompleteAuthenticateAsClient(IAsyncResult result)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
....
现在,如果我只改变客户端的配置:
<endpoint address="net.tcp://localhost:xxxxx/xxxx/xxx/1.0"
binding="netTcpBinding" bindingConfiguration="MyTcpEndpoint"
contract="Service.IMyService" name="TcpEndpoint">
<identity>
<dns />
</identity>
</endpoint>
一切正常,我的服务器很高兴地报告说它是由托管我网站的AppPool的服务帐户调用的。一切都好。
我现在的问题是:为什么这有效?这是做什么的?仅通过反复试验就得出了这个解决方案。对我而言,似乎所有<dns />
标签都告诉客户端使用默认DNS进行身份验证,但是不管怎么说它不会这样做吗?
更新
经过一些研究和反复试验,我仍然没有找到这个问题的答案。
在某些情况下,如果我没有提供<dns />
,则会收到Credentials rejected
错误,但如果我提供<dns value="whatever"/>
配置,则会有效。为什么呢?
答案 0 :(得分:16)
<dns/>
标记允许客户端验证服务器标识。例如,如果您说<dns value="google.com"/>
,它将验证WCF服务器是否提供google.com身份。既然你说<dns/>
它可能只允许每个人为你服务。
答案 1 :(得分:7)
MSDN的"Service Identity and Authentication"解释说,端点身份部分支持针对网络钓鱼方案的客户端安全预防措施。
来自MSDN:
客户端启动与端点的通信后 service对客户端进行身份验证,客户端比较 端点标识值与端点的实际值 验证过程返回。如果匹配,客户将得到保证 它已联系预期的服务端点。 这个用作 通过阻止客户端防止网络钓鱼 重定向到恶意服务托管的端点。
另请参阅MSDN的"Service Identity Sample"。
答案 2 :(得分:0)
不是答案,但如果您通过代码创建EndpointAddress,那么相同的“技巧”仍然有效:
// does fail on some machines for some users
// (I have no explanation here - just crazy)
var address = new EndpointAddress(new Uri(url));
// will work and the dns entry doesn't matter
address = new EndpointAddress(new Uri(url), UpnEndpointIdentity.CreateDnsIdentity(""));
这很奇怪,我不知道为什么这有效,但似乎有所帮助。