Call WCF on NetTcpBinding from anonymous website

Our project uses WCF services hosted on multiple machines. The binding used can be chosen from predefined options. One of the options is NetTcpBinding.

A website hosted in IIS with anonymous authentication is used to consume the WCF service. When the service is hosted on the same machine everything works, but when some other machine hosts the service (no domain) an exception is thrown

<Exception>
   <ExceptionType>
      System.IdentityModel.Tokens.SecurityTokenValidationException, 
      System.IdentityModel, Version=4.0.0.0, Culture=neutral, 
      PublicKeyToken=b77a5c561934e089
   </ExceptionType>
   <Message>
      The service does not allow you to log on anonymously.
   </Message>
   <StackTrace> ... </StackTrace>
   <ExceptionString> ... </ExceptionString>
</Exception>

Repro

For investigating the issue we created a small service and a website that calls the service from a button click. The interesting parts of the code is shown below.

# Create a selfsigned certificate from the command prompt.
makecert -sky exchange -r -n CN=other_machine -pe -a sha1 -len 2048 
   -ss My -sr LocalMachine c:\other_machine.cer

The other_machine.cer should be imported in Trusted People on all machines that call the WCF service.

// Main of the console app that hosts the calculate service
var machine = System.Net.Dns.GetHostName();
var address = string.Format("net.tcp://{0}:8000/calc.svc", machine);
var binding = new NetTcpBinding(SecurityMode.Transport);
var contract = typeof(ICalculate);
using (var host = new ServiceHost(typeof(CalculateService)))
{
  host.Credentials.ServiceCertificate.Certificate = 
      GetCertificateByThumbprint("thumbprint_here");
  var endpoint = host.AddServiceEndpoint(contract, binding, address);
  host.Open();
  Console.WriteLine("Listening on {0}\nPress <CR> to stop.", address);
  Console.ReadLine();
  host.Close();
}

Host the service in the console app and configure tracing to capture the exception.

// btn1_click code
var binding = new NetTcpBinding(SecurityMode.Transport);
var address = "net.tcp://other_machine:8000/calc.svc";
using (var proxy = new NetTcpService.CalculateProxy(binding, address))
{
    var r = new Random();
    var a = r.Next(1, 199);
    var b = r.Next(1, 199);
    var result = proxy.Add(a, b);
    btn1.Text = string.Format("{0} + {1} = {2}", a, b, result);
}

The website is hosted with all the defaults: DefaultAppPool, Anonymous Authentication.

After clicking the button the exception was logged to the trace file. We’ve got a repro.

Investigation

Internet is full of solutions. We’ve tried setting the credentials of the website, change application pool and allowed anonymous logons on windowsauthentication credentials. This last “solution” triggered use to look into the defaults of the NetTcpBinding. Seems the default of the clientCredentialType is Windows.

Solution

We’re not interested in the windows credentials and do want to allow anonymous access to our calculate service. The solution in the repro code above is to set the clientCredentialType to none.

var binding = new NetTcpBinding(SecurityMode.Transport);
// add this to the console app and the btn1_click
binding.Security.Transport.ClientCredentialType = 
    TcpClientCredentialType.None;

Now we can access the webservice from all clients including a website with anonymous authentication.

References

About erictummers

Working in a DevOps team is the best thing that happened to me. I like challenges and sharing the solutions with others. On my blog I’ll mostly post about my work, but expect an occasional home project, productivity tip and tooling review.
This entry was posted in Development and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.