ここで奇妙な状況になっています。動作しましたが、理由がわかりません。状況は次のとおりです。
私のアプリケーション(Webサイト)が呼び出さなければならない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>
Webサイトを実行してサービスを呼び出すと、次のエラーが発生します。
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"/>
configを指定すると機能します。どうして?
<dns/>
タグを使用すると、クライアントはサーバーのIDを確認できます。たとえば、あなたが<dns value="google.com"/>
WCFサーバーがgoogle.com IDを提供することを確認します。あなたが言うので<dns/>
それはおそらく、誰もがあなたに仕えることを許可するだけです。
詳細は Service Identity and Authentication にあります。
MSDNの "Service Identity and Authentication" は、エンドポイントIDセクションがフィッシングスキームに対するクライアント側のセキュリティ対策を可能にすることを説明しています。
MSDNから:
クライアントがエンドポイントへの通信を開始し、サービスがクライアントに対して自身を認証した後、クライアントはエンドポイントID値を、エンドポイント認証プロセスが返した実際の値と比較します。それらが一致する場合、クライアントは、予期されたサービスエンドポイントに接続したことを保証します。 これは、悪意のあるサービスによってホストされているエンドポイントにクライアントがリダイレクトされるのを防ぐことにより、フィッシングに対する保護として機能します。
MSDNの "Service Identity Sample" も参照してください。
答えではありませんが、コードで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(""));
これは奇妙で、なぜこれが機能するのかはわかりませんが、役立つようです。