Search code examples
wcfkerberosspnegospnnegotiate

Is the default default SPN for a WCF Client `host/myhostname` or `http/myhostname` and why?


Due to this question the default behavior when no identity is specified is host/myhostname.

However this seems not totally true.

I have a SOAP WCF Service (it's a Dynamics NAV Webservice but this should not matter for the following since the question is totally about client perspective) that does not work if I don't specify any identity.

The server is actually running under a domain user account. host/myhostname is specified but not for this user account, only for the machine account. http/myhostname is specified for this domain user account.

Lets look into three scenarios:

No identity is specified

I create the EndpointAddress with the following code:

new EndpointAddress(new Uri(endpoint))

In this scenario the following is happening:

  • HTTP POST without Authorization header.
  • Response with WWW-Authenticate: Negotiate.
  • HTTP POST with Authorization: Negotiate XXX header. XXX are 1584 BASE64 encoded bytes, starting with 96 130 6. I can't find any readable ASCII inside it.
  • Response with Authorization: Negotiate XXX header. XXX are 126 BASE64 encoded bytes. I can't find any readable ASCII inside it.
  • HTTP POST with Authorization: Negotiate XXX header. XXX are 1527 BASE64 encoded bytes. I can't find any readable ASCII inside it.
  • Response with WWW-Authenticate: Negotiate XXX header. XXX are 113 BASE64 encoded bytes. I can't find any readable ASCII inside it.
  • At this Point the client throws an exception. The inner exception message is The target principal name is incorrect.

Mannually set the identity to host/myhostname or a wrong string.

I create the EndpointAddress with the following code:

var identity = EndpointIdentity.CreateSpnIdentity(@"host/myhostname");
var endpointAddress = new EndpointAddress(new Uri(endpoint), identity); 

If host/myhostname would be the default setting, the code above would just explicit specify this default setting. So I would expect the same behavior. But this works. It seems the I fall back to NTLM. So there must be a difference.

This is whats happening:

  • HTTP POST without Authorization header.
  • Response with WWW-Authenticate: Negotiate.
  • HTTP POST with Authorization: Negotiate XXX where XXX are 40 BASE64 encoded bytes. The first bytes are the ASCII letters NTLMSSP.
  • Response with WWW-Authenticate: Negotiate XXX where XXX are 270 BASE64 encoded bytes. The first bytes are the ASCII letters NTLMSSP. Also the FQDN seems to be encoded as ASCII.
  • HTTP POST with Authorization: Negotiate XXX, where XXX are 590 BASE64 encoded bytes. No ASCII letters this time tho.
  • Response with the Payload.

An interesting fact: If I specify the identity to any wrong String, I have the exactly same behavior. So for example if I specify the EndpointAddress with this code:

var identity = EndpointIdentity.CreateSpnIdentity(@"thisIsTotallyWrongLoremIpsum");
var endpointAddress = new EndpointAddress(new Uri(endpoint), identity);

I also get the behavior above with the fallback to NTLM.

I correctly set the identity to http/myhostname

Now when I specify the SPN to http/myhostname which is set and seems to be the right choice due RFC 4559 it works. This is the configuration:

var identity = EndpointIdentity.CreateSpnIdentity(@"http/myhostname");
var endpointAddress = new EndpointAddress(new Uri(endpoint), identity);

And this is whats happening:

  • HTTP POST without Authorization header.
  • Response with WWW-Authenticate: Negotiate.
  • HTTP POST with Authorization: Negotiate XXX header. XXX are 1580 BASE64 encoded bytes. No ASCI signs.
  • Response with the Payload.

This question is not about hot to get it to work but about understanding. Whats confusing me is the difference between the first and the second example. My thoughts are:

  1. If the default identity is host/myhostname,
  2. it should make no difference to manually specify the identity to host/myhostname,
  3. but there is a difference
  4. so this can't be default identity.

So my questions are

  1. What is the actual default behavior, and
  2. why is http/myhostname not selected as the default SPN as it should due to RFC4559?

And/or did I understood something completely wrong?


Solution

  • There were two specific questions presented at the end of the problem statement; listing them below.

    Q. 1) What is the actual default behavior?

    A. If no identity is specified, and the client credential type is Windows, the default is SPN with the value set to the hostname part of the service endpoint address prefixed with the "host/" literal. This setting takes advantage of Windows Kerberos security if the service is running under one of the system accounts or under a domain account that has an associated SPN name with it and the computer is a member of a domain within an Active Directory environment.

    Q. 2) Why is http/myhostname not selected as the default SPN as it should due to RFC4559?

    A. With a web browser you would connect as http/myhostname. But with the WCF client, the default is to connect as host/myhostname as per the above. And it is definitely going to connect to host/myhostname under the scenario #2 where you set the identity to host/myhostname.

    Reference for Q1 and Q2 above: Service Identity and Authentication

    COMMENT: Fallback to NTLM occurs for a variety of reasons. The way to figure it out is to understand why Kerberos failed - SPN problems are the main cause. A great reference for diagnosing SPN problems is the Blog of Brian Murphy-Booth - The biggest mistake: ServicePrincipalName’s.

    After looking through the Brian Murphy blog, it was subsequently found by the original questioner that within the problem scenario, a port was being used. "The port is not used when the SPN is automatically determined. So http://foo.example.com:1234 leads to host/foo.example.com as SPN. And when the SPN does not exist it does fall back to NTLM and when the SPN does exist but not for the right user it throws the The target principal name is incorrect exception."