Home > Blockchain >  The HTTP request is unauthorized with client authentication scheme Negotiate. The authentication hea
The HTTP request is unauthorized with client authentication scheme Negotiate. The authentication hea

Time:09-17

I am using a desktop application on a client pc to communicate with an IIS WCF web service running on a server, using WsHttpBinding to pass over the Windows user credentials. The application has worked well for many years, but now we are trying to have it communicate over HTTPS instead of just HTTP.

On the server side, we add an SSL certificate to the IIS website and change the WCF web.config to use Transport security for the binding definition:

      <wsHttpBinding>
        <binding name="WSHttpBinding_IService1">
          <readerQuotas maxArrayLength="2147483647" />
          <security mode="Transport" />
        </binding>
      </wsHttpBinding>

On the client side, the client object used to connect to the service uses Transport security mode to account for the HTTPS communication mode:

Dim serverURL as String = ReadServerURL()
Dim client As Service1Client
Dim binding As Channels.Binding
Dim dcso As ServiceModel.Description.DataContractSerializerOperationBehavior

binding = New WSHttpBinding("WSHttpBinding_IService1")

If serverURL.ToLower.StartsWith("https://") Then
  CType(binding, WSHttpBinding).Security.Mode = SecurityMode.Transport
Else
  CType(binding, WSHttpBinding).Security.Mode = SecurityMode.Message
End If

CType(binding, WSHttpBinding).Security.Message.ClientCredentialType = MessageCredentialType.Windows
CType(binding, WSHttpBinding).Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows 

binding.ReceiveTimeout = New TimeSpan(0, 10, 0)

client = New Service1Client(binding, New EndpointAddress(serverURL))

client.ClientCredentials.Windows.ClientCredential = CType(CredentialCache.DefaultCredentials, NetworkCredential)
client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation 

Some customers use Kerberos to pass the Windows credentials to another server, which is why we use Delegation.

Most customers have opted to use self-signed certificates because they are only using internal servers.

In IIS, the WCF site has Windows Authentication enabled, with both Negotiate and NTLM providers enabled.

enter image description here

This approach seems to work fine at most customer sites, but at least one is experiencing this error:

The HTTP request is unauthorized with client authentication scheme 'Negotiate. The authentication header received from the server was 'Negotiate oXlwcKADCgEBomkEZ2....oZSQ='.

I am not sure where this alternate 'Negotiate oXlwcK...' provider is coming from in IIS or how to configure the client to properly communicate with it. Is this an IIS configuration issue, an issue with the WCF service code and/or the client application code, or could it be a network/domain issue? Any help is greatly appreciated.

CodePudding user response:

If you see this problem calling a WCF Service hosted on the same machine, you may need to populate the BackConnectionHostNames registry key.

  1. In regedit, locate and then click the following registry subkey: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0

  2. Right-click MSV1_0, point to New, and then click Multi-String Value.

  3. In the Name column, type BackConnectionHostNames, and then press ENTER.

  4. Right-click BackConnectionHostNames, and then click Modify. In the Value data box, type the CNAME or the DNS alias, that is used for the local shares on the computer, and then click OK.

Type each host name on a separate line.

See Calling WCF service hosted in IIS on the same machine as client throws authentication error for details.

CodePudding user response:

I was able to solve this issue by adding an UpnEndpointIdentity object to the EndpointAddress constructor.

For the parameter in the UpnEndpointIdentity I had to use the user name which is displayed in the "Identity" column of the IIS Application Pool. E.g. var id = new UpnEndpointIdentity("DOMAIN\user.name");

This only worked on .NET Framework but not in .NET Core 3.1 (I didn't try .NET Core 5.0).

  • Related