'How do I solve SecurityNegotiationException and InvalidCredentialException in WCF

So I've written a small game and wish for the game to be playable over the internet.

I've been testing the game just through localhost using these configs:

Client Winapp Application:

App.Config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <system.serviceModel>
    <client>
        <endpoint name ="CommandBoard"
                  address="net.tcp://localhost:9000/commandboard"
                  binding = "netTcpBinding"
                  contract="CommandBoardServiceLibrary.ICommandBoardService"/>
    </client>
  </system.serviceModel>
</configuration>

While in the Client Winform Code I have it connecting like this

ChannelFactory<ICommandBoardService> remoteFactory= new ChannelFactory<ICommandBoardService>("CommandBoard");
ICommandBoardService proxy = remoteFactory.CreateChannel();

Next, to host the service I create a console app.

the App.config is basic. I changed nothing, only in the actual code.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

Console app code:

static void Main(string[] args)
{
    using (ServiceHost host = new ServiceHost(typeof(CommandBoardServiceLibrary.CommandBoardService)))
    {
        host.AddServiceEndpoint(typeof(
            CommandBoardServiceLibrary.ICommandBoardService),
            new NetTcpBinding(),
            "net.tcp://localhost:9000/commandboard");
        host.Open();

        Console.ReadLine();
     }
}

Running both the client and the host at the same time works perfectly on my computer.

Now when I change the client's App.Config to

<client>
    <endpoint name ="CommandBoard"
              address="net.tcp://23.122.59.211:9000/commandboard"
              binding = "netTcpBinding"
              contract="CommandBoardServiceLibrary.ICommandBoardService"/>
</client>

and run it on a different computer on a different Network I get the following error: System.ServiceModel.Security.SecurityNegotiationException: The server has rejected the client credentials. ---> System.Security.Authentication.InvalidCredentialException: The server has rejected the client credentials. ---> System.ComponentModel.Win32Exception: The logon attempt failed

Where is the source of this error? Have a configured it incorrectly? Or am I missing something?

EDIT: Web.config for the WCF service

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>


Solution 1:[1]

All configuration of WCF is done inside the <system.serviceModel> tag. This is true for host and client. Since your host service has no serviceModel tag, WCF will apply the default for netTcpBinding which is transport security.

The client has a service model tag, but no security settings, so it will try the default for netTcpBinding too.

You can use "WCF Service configuration editor" tool, that comes with Visual Studio, to set up binding and security for both your client and host, but basically, you will need to override defaults.

Create a configuration for the endpoint on both client and server and bindingconfiguration equal to "", like this:

 <endpoint address=""
           binding="netTcpBinding"
           bindingConfiguration=""
           name="NetTcpBindingEndpoint"
           contract="WCFHostService.IMyService">

Here you can find a complete guide for netTcpBinding.

Solution 2:[2]

Based on your configuration and the fact it does indeed work locally, means you've configured a portion correctly. However you should do this for your Host Portion.

<endpoint address= ""
     binding="netTcpBinding"
     bindingConfiguration= ""
     name= "NetTcpBindingEndpoint"
     contract="Reference.To.Your.Interface.IMyService">

     <identity>
         <dns value="localhost" />
     </identity>
</endpoint>

Now one of the important parts, you'll need to physically expose your metadata. Without that endpoint configured, you'll have severe issues.

<endpoint address="mex"
     binding="mexTcpBinding"
     bindingConfiguration= ""
     name="MexTcpBindingEndpoint"
     contract="IMetadataExchange" />

<host>
    <baseAddress>
         <add baseAddress="net.tcp://localhost:8523/WcfTestService" />
    </baseAddress>
</host>

Now that you've configured that portion of your host, you need to physically install the service. You simply publish, build, install the executable, then verify the service is indeed running on your machine through Services

This is the other part where I believe you're having an issue, through the svc utility. You can't generate a valid URI for your service. If you've configured the Host correctly this will work:

  1. Right Click in your Client Application
  2. Add Service Reference
  3. Set the URI to: net.tcp://localhost:8523/ServiceName then click Go. It should resolve, or you can attempt to automatically resolve. The Port number may need to be changed.

Once you have your reference it should be as easy as:

  WCFTestService.MyServiceClient myService =
     new WCFTestService.MyServiceClient();
  MessageBox.Show(myService.DoWork("Hello World!"));
  myService.Close();

You create the Client object, then you expose the method from the interface. This approach should also alleviate those security issues. I have a feeling that is because an invalid URI is being used.

You may need to run Visual Studio as an Administrator also.

I hope that helps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Mortensen
Solution 2 Peter Mortensen