Hi all,
I'm having a strange situation here. I got it working, but I don't understand why. Situation is as follows:
There is a WCF service which my application (a website) has to call. The WCF service exposes a netTcpBinding and requires Transport Security (Windows).
Client and server are in the same domain, but on different servers.
So generating a client results in the following config (mostly defaults)
<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>
When I run the website and make the call to the service, I get the following error:
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)
....
Now, if I just alter the configuration of the client like so:
<endpoint address="net.tcp://localhost:xxxxx/xxxx/xxx/1.0"
binding="netTcpBinding" bindingConfiguration="MyTcpEndpoint"
contract="Service.IMyService" name="TcpEndpoint">
<identity>
<dns />
</identity>
</endpoint>
everything works and my server happily reports that it got called by the service account which hosts the AppPool for my website. All good.
My question now is: why does this work? What does this do? I got to this solution by mere trial-and-error. To me it seems that all the <dns />
tag does is tell the client to use the default DNS for authentication, but doesn't it do that anyway?
Thanks for providing me with some insight.
UPDATE
So after some more research and trial-and-error, I still haven't found an answer to this problem.
In some cases, if I don't provide the <dns />
, i get the Credentials rejected
error, but if I provide the <dns value="whatever"/>
config, it works. Why?