20
votes

I've looked through a ton of SO articles, and even other sites, but can't seem to get this service working. I have a SOAP service I'm trying to hit and it's configured like this:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
        <binding name="PROVIDERSSoapBinding">
            <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Ntlm" proxyCredentialType="None" realm="" />
            </security>
        </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://xxx.xx.xx.xxx:9011/provider/services/PROVIDERS"
            binding="basicHttpBinding" bindingConfiguration="PROVIDERSSoapBinding"
            contract="ServiceReference1.ProviderRemote" name="PROVIDERS" />
    </client>
</system.serviceModel>

However, I'm getting the following error when hitting it from my console application:

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

Can somebody help me out?

7
Have you tried a different credential type to make sure it works at all?iMortalitySX
Maybe try first with 'security mode' set to 'None' to be sure that it works without security in the first instance, and then slowly dial up the security settingsChamila Chulatunga
What is your environment? (IIS, Self Host, etc)iMortalitySX
Are the client and service located on the same machine? If so this may help: support.microsoft.com/kb/896861David Martin
@iMortalitySX, I am hitting a server internally on the network. Therefore, the service is setup on that server.Mike Perrenoud

7 Answers

8
votes

You can eliminate the client from the problem by using wftech, this is an old tool but I have found it useful in diagnosing authentication issues. wfetch allows you to specify NTLM, Negotiate and kerberos, this may well help you better understand your problem. As you are trying to call a service and wfetch knows nothing about WCF, I would suggest applying your endpoint binding (PROVIDERSSoapBinding) to the serviceMetadata then you can do an HTTP GET of the WSDL for the service with the same security settings.

Another option, which may be available to you is to force the server to use NTLM, you can do this by either editing the metabase (IIS 6) and removing the Negotiate setting, more details at http://support.microsoft.com/kb/215383.

If you are using IIS 7.x then the approach is slightly different, details of how to configure the authentication providers are here http://www.iis.net/configreference/system.webserver/security/authentication/windowsauthentication.

I notice that you have blocked out the server address with xxx.xx.xx.xxx, so I'm guessing that this is an IP address rather than a server name, this may cause issues with authentication, so if possible try targeting the machine name.

Sorry that I haven't given you the answer but rather pointers for getting closer to the issue, but I hope it helps.

I'll finish by saying that I have experienced this same issue and my only recourse was to use Kerberos rather than NTLM, don't forget you'll need to register an SPN for the service if you do go down this route.

10
votes

Try setting 'clientCredentialType' to 'Windows' instead of 'Ntlm'.

I think that this is what the server is expecting - i.e. when it says the server expects "Negotiate,NTLM", that actually means Windows Auth, where it will try to use Kerberos if available, or fall back to NTLM if not (hence the 'negotiate')

I'm basing this on somewhat reading between the lines of: Selecting a Credential Type

6
votes

If both your client and service is installed on the same machine, and you are facing this problem with the correct (read: tried and tested elsewhere) client and service configurations, then this might be worth checking.

Check host entries in your host file

%windir%/system32/drivers/etc/hosts

Check to see if you are accessing your web service with a hostname, and that same hostname has been associated with an IP address in the hosts file mentioned above. If yes, NTLM/Windows credentials will NOT be passed from the client to the service as any request for that hostname will be routed again at the machine level.

Try either of the following

  • Remove the host entry of that hostname from the hosts file
  • OR
  • If removing host entry is not possible, then try accessing your service with another hostname. You might also try with IP address instead of hostname

Edit: Somehow the above situation is relevant on a load-balanced scenario. However, if removing the host entries is not possible, then disabling loop back check on the machine will help. Refer method 2 in the article https://support.microsoft.com/en-us/kb/896861

4
votes

We encountered this issue and discovered that the error was being thrown when using (IE in our case) the browser logged in as the process account, then changing the session log in through the application (SharePoint). I believe this scenario passes two authentication schemes:

  1. Negotiate
  2. NTLM

The application hosted an *.asmx web service, that was being called on a load balanced server, initiating a web service call to itself using a WCF-like .NET3.5 binding.

Code that was used to call the web service:

public class WebServiceClient<T> : IDisposable
{
    private readonly T _channel;
    private readonly IClientChannel _clientChannel;

    public WebServiceClient(string url)
        : this(url, null)
    {
    }
    /// <summary>
    /// Use action to change some of the connection properties before creating the channel
    /// </summary>
    public WebServiceClient(string url,
         Action<CustomBinding, HttpTransportBindingElement, EndpointAddress, ChannelFactory> init)
    {
        var binding = new CustomBinding();
        binding.Elements.Add(
            new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8));
        var transport = url.StartsWith("https", StringComparison.InvariantCultureIgnoreCase)
                            ? new HttpsTransportBindingElement()
                            : new HttpTransportBindingElement();
        transport.AuthenticationScheme = System.Net.AuthenticationSchemes.Ntlm;
        binding.Elements.Add(transport);

        var address = new EndpointAddress(url);

        var factory = new ChannelFactory<T>(binding, address);
        factory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

        if (init != null)
        {
            init(binding, transport, address, factory);
        }

        this._clientChannel = (IClientChannel)factory.CreateChannel();
        this._channel = (T)this._clientChannel;
    }

    /// <summary>
    /// Use this property to call service methods
    /// </summary>
    public T Channel
    {
        get { return this._channel; }
    }
    /// <summary>
    /// Use this porperty when working with
    /// Session or Cookies
    /// </summary>
    public IClientChannel ClientChannel
    {
        get { return this._clientChannel; }
    }

    public void Dispose()
    {
        this._clientChannel.Dispose();
    }
}

We discovered that if the session credential was the same as the browser's process account, then just NTLM was used and the call was successful. Otherwise it would result in this captured exception:

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

In the end, I am fairly certain that one of the authentication schemes would pass authentication while the other wouldn't, because it was not granted appropriate access.

2
votes

You need to set the NTAuthenticationProviders to NTLM

MSDN Article: https://msdn.microsoft.com/en-us/library/ee248703(VS.90).aspx

IIS Command-line (http://msdn.microsoft.com/en-us/library/ms525006(v=vs.90).aspx):

 cscript adsutil.vbs set w3svc/WebSiteValueData/root/NTAuthenticationProviders "NTLM"
1
votes

I know this question is old, but the solution to my application, was different to the already suggested answers. If anyone else like me still have this issue, and none of the above answers works, this might be the problem:

I used a Network Credentials object to parse a windows username+password to a third party SOAP webservice. I had set the username="domainname\username", password="password" and domain="domainname". Now this game me that strange Ntlm and not NTLM error. To solve the problems, make sure not to use the domain parameter on the NetworkCredentials object if the domain name is included in the username with the backslash. So either remove domain name from the username and parse in domain parameter, or leave out the domain parameter. This solved my issue.

0
votes

I'm using .NET 5. In my case I had to downgrade System.ServiceModel.Http.dll from 4.8.1 to 4.4.4. Didn't have much time to dig deeper the root cause.