views:

902

answers:

1

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?

+2  A: 

<dns/> tag allows the client to verify the server identity. For example if you said <dns value="google.com"/> it would verify that the WCF server provides google.com identity. Since you say <dns/> it probably just allows everybody to serve you.

More info at Service Identity and Authentication

Vitalik
Well, after reading through that page again, and trying some different configurations, it's still not resolved. Even if I supply `my-crappy-unexisting-dummy-domain.com` , it still works. I figured, it must try to make the request and then fall back to a default, but I cannot find anything in the logging that would suggest the dns server or the application server even tried to authenticate against that domain... So my question is still unsolved. Thanks for helping me though!
Roel
I think you would need to have a certificate with a domain name in order for the client to authenticate.
Vitalik