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

31,352

Solution 1

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.

Solution 2

It just means your client and server are using different authentication scheme.

In your client config, you've set up a

<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />

and a message security

<message clientCredentialType="UserName" algorithmSuite="Default" />

So you might be getting errors because of this. These links might help you.

Also, in your client config

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

Change the behaviorConfiguration from behaviorConfiguration="OMSServiceBehavior" to behaviorConfiguration="OMWebServices.QueueServiceBehavior"

Also did you try to use TransportCredentialOnly? If not, it might be good to try this http://msdn.microsoft.com/en-us/library/ff648505.aspx

<security mode="TransportCredentialOnly">
    <transport clientCredentialType="Windows" />
</security>

Solution 3

My problem with this error was not config related but specific to a WCF Service calling another on the same machine.

Because this affected a fleet of new servers that were partly provisioned through a C# console app, I solved it by executing code like this through the affected servers:

const string userRoot = "HKEY_LOCAL_MACHINE";
const string subkey = @"SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0";
const string keyName = userRoot + @"\" + subkey;
Registry.SetValue(keyName, "BackConnectionHostNames", hostnamesOnServer.ToArray(), RegistryValueKind.MultiString);

Reboot wasn't required on Windows Server 2012.

Share:
31,352
xr280xr
Author by

xr280xr

Updated on July 12, 2022

Comments

  • xr280xr
    xr280xr almost 2 years

    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?

  • xr280xr
    xr280xr about 10 years
    Thanks minerva. But it seems to be telling me the authentication schemes are the same; Negotiate. I the behavior spelling was a thread typo, good catch. I'm not using the behavior anymore anyway. For the <message /> config, I believe that is the default value for that property anyway (except None instead of Basic256) it was there because VS generated it. I removed it and got the same result. I just tried TransportCredentialOnly and it works, but I want Transport in order to secure all communication. What does it mean that that works? Both use SSL and both use the same credentials, don't they?
  • minerva
    minerva about 10 years
    @drpcken provided an explanation of Transport and TransportCredentialsOnly. Here's the link to his answer.
  • minerva
    minerva about 10 years
    @Anand also provide an explanation of Transport and TransportCredentialOnly
  • minerva
    minerva about 10 years
    Also noticed that the client webconfig is missing an s contract="OMQueueService.IQueueService" should be contract="OMWebServices.IQueueService"
  • minerva
    minerva about 10 years
    This might be the most comprehensive one that might help you. If you're doing internet & transport, you'll need to install a SSL certificate on IIS.
  • xr280xr
    xr280xr about 10 years
    Ah, I was misremembering what TransportCredentialsOnly did since I don't use it. Verified the SSL cert is installed. I don't know why, but the contract is correct as written (generated that way by svcutil). I think the fact that calling the service with TransportCredentialsOnly works proves that.