asp.netweb-serviceswcfauthenticationiis

401 Client 'Negotiate', Server 'Negotiate,NTLM' When Calling WCF Server to Server


Ok, I've read every thread & question I can find with this error and surprisingly have not found a solution. I'm trying to require Windows authentication on my IIS hosted WCF service (.NET 4.0) which, until now, has been optional. I have had a Windows authentication enabled endpoint available on the server for a while with several remote applications successfully using it. I'm now trying to switch our web applications and other server apps that use the WCF service over to this secured endpoint by giving them the exact same client configuration as the working remote clients, but the server apps are receiving a 401 with the message:

The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.]

I have Anonymous and Windows authentication enabled for the WCF hosting site. The web application I've started with is hosted on a different server than the WCF service and is running on ASP.NET 2.0 and Windows Server 2008 R2 Enterprise. I have both created a client behavior with allowNtlm and set the NetworkSecurity: LAN Manager authentication level to Send LM & NTLM... on the client end. On the hosting end, it is set to Send NTLMv2 Response Only...I don't know if that affects how the server/service handles authentication. I've also tried setting allowedImpersonationLevel to Impersonation on the client which, thankfully, didn't work (because impersonation shouldn't be necessary). We seem to get the same result for a Windows service and console app running on the same server as the web app.

Here is my server config:

<binding name="WindowsSecuredBinding">
    <security mode="Transport">
        <transport clientCredentialType="Windows" />
    </security>
</binding>
...
<service behaviorConfiguration="OMWebServices.QueueServiceBehavior"
    name="OMWebServices.QueueService">
    <endpoint address="" binding="basicHttpBinding" name="QueueEndpoint"
      bindingName="" contract="OMWebServices.IQueueService" />
    <endpoint binding="basicHttpBinding" bindingConfiguration="WindowsSecuredBinding"
      name="QueueSecuredEndpoint" contract="OMWebServices.IQueueService" />
    <endpoint address="mex" binding="mexHttpBinding" name="QueueMetadataEndpoint"
      contract="IMetadataExchange" />
  </service>
...
<behavior name="OMWebServices.QueueServiceBehavior">
    <serviceMetadata httpGetEnabled="true" />
    <serviceDebug includeExceptionDetailInFaults="true" />
</behavior>

And here is the client config:

<endpoint address="https://.../QueueService.svc" binding="basicHttpBinding" bindingConfiguration="QueueSecuredEndpoint" behaviorConfiguration="OMServiceBehavior" contract="OMQueueService.IQueueService" name="QueueSecuredEndpoint" />

<binding name="QueueSecuredEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
  <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
  <security mode="Transport">
    <transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
  </security>
</binding>
....
<!-- The behavior I tried that didn't make a difference -->
<behavior name="OMServiceBehavior">
  <clientCredentials>
    <windows allowedImpersonationLevel="Impersonation" allowNtlm="True"/>
  </clientCredentials>
</behavior>

My first question is, what is this error message really telling me? It says the client scheme is Negotiate and the server's responding with Negotiate,NTLM. If the server offers Negotiate and and client is using Negotiate, what's the problem?

Second question is, obviously, what's wrong and how do I make it work?

EDIT
Well this is stupid. The problem seems to be there are no credentials being passed. Way back when the web site was in development, I started writing code to explicitly set the credentials in code, but in the process, found that it was already working without explicitly setting them. So that code has remained commented out. This was running on IIS 6. Now running on IIS 7, it seems to only work if I explicitly set the credentials in my code. Can I get it automatically using the w3wp process' account?


Solution

  • To answer the first question, the error message is telling me exactly what it says; I'm not authorized. The line telling me the client authentication scheme and server header is just extra info, not an indication of a conflict. It's actually confirmation that the configuration is correct.

    In the staging environment, the problem is being masked because the WCF service and the web application are hosted on the same server. The problem is the web app's site is configured to use IUSR (or IUSR_Server), a local account, for anonymous users by default. This is the user that is being passed (which I believe is equal to CredentialCache.DefaultNetworkCredentials). When they're on different servers, WCF on server 2 obviously can't authenticate a server 1 user. The solution is in IIS, right click Anonymous Authentication > Edit...> check Application pool identity (which is a domain account in my case) or enter a domain account for Specific user.