3

I'm trying to connect to a third-party SOAP service via a c# app. The following code works when running the app on a Windows machine:

var ws = new MyWebServiceClient();
ws.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("myusername", "mypassword", "mydomain");
var response = ws.SomeEndpoint();
Element xmlResult = response.Result.SomeEndpoint;
...

But if I run the same code from Linux or Mac OS, it fails with:

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

I have a python app that can consume that same SOAP service when running on any operating system without running into issues, so the problem isn't in my linux distribution/setup.

Has anyone seen a similar issue with .NET core or found a workaround?

I found this issue report that suggests that the earlier versions of .NET core had limitations/bugs that could cause behavior similar to what I'm seeing, but it claims that those issues were resolved after RC2.

Assuming that issue report is wrong and that the issue still remains in the Linux/Mac distribution of .NET core, does anyone know how I can get the CredentialCache workaround, suggested in that article, working with a SOAP client? I'm pretty new to .NET and super new to .NET soap clients, so I apologize if that's a naive question.

It seems that, for non-Windows, .NET core is failing to attempt NTLM after Negotiate fails. I know, from the python app, that NTLM works with this particular SOAP service. How can I force it to skip "Negotiate" and and go straight to NTLM? It seems that that is what the CredentialCache workaround, from the above article, is doing. I just can't figure out how to make that work with a SOAP service...

McGuireV10
  • 9,572
  • 5
  • 48
  • 64
Troy
  • 21,172
  • 20
  • 74
  • 103
  • can you try if it work by adding a line: `ws.ClientCredentials.Windows.AllowNtlm = true;` ? Also how is your bindings look like? Are you using WSHttpBinding? – Chun Liu Mar 08 '18 at 07:17
  • Could you capture the network traffic for the python app and for the C# app and compare them? – Marius Mar 08 '18 at 09:48
  • @ChunLiu - I had read about the `AllowNtlm` option, but it appears that it was deprecated, some time ago, and is now completely _absent_ as an option. – Troy Mar 08 '18 at 14:38
  • @Marius - I have checked the traffic of the python app, which is how I verified that it's using the NTLM option. The C# app is more of a black box though, so the pre-encrypted traffic is not really accessible. I understand that with the full/Windows version of Visual Studio, it's possible to have it download the source/sourcemaps such that they are debuggable, but, from what what I understand, that option hasn't been added to VS Code yet (or if it IS in VS Code, it is done a completely different way - I'm really new to VS). – Troy Mar 08 '18 at 14:42
  • Yes, at the moment you can not easily step into framework code when using VS Code. This [feature is planned](https://github.com/OmniSharp/omnisharp-vscode/wiki/Debugging-into-the-.NET-Framework-itself) for .NET Core 2.1. – Marius Mar 09 '18 at 12:21

2 Answers2

2

.Net Core SOAP client wih NTLM Authentication and CredentialCache

As described on MSDN and here,

BasicHttpBinding basicHttpBinding = new BasicHttpBinding();

basicHttpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;

basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;

EndpointAddress endpoint = new EndpointAddress("http://myservice");

var factory = new ChannelFactory<IMyService>(basicHttpBinding, endpoint);
CredentialCache myCredentialCache = new CredentialCache();

NetworkCredential myCreds = new NetworkCredential("username", "password", "domain");
myCredentialCache.Add("ContoscoMail", 45, "NTLM", myCreds);
factory.Credentials.Windows.ClientCredential = 
         myCredentialCache.GetCredential("ContosoMail", 45, "NTLM");

var client = factory.CreateChannel(); 

// ... use the webservice

Update: it's a bug fixed in 2.1

As already encountered here and fixed as a bug here, it should work with .net core 2.1 (not released and scheduled for Q1 2018). So right now, you should try to use another type of authentication when connecting from Linux (look at RuntimeInformation.IsOSPlatform).

Fab
  • 14,327
  • 5
  • 49
  • 68
  • Maybe the above goes into some C# magic that I'm not familiar with yet... but, for me, the above gives me `'ChannelFactory' does not contain a definition for 'ClientCredentials'...`. – Troy Mar 10 '18 at 14:36
  • @Troy I've fixed it. Tried with System.ServiceModel.Http 4.3.0 – Fab Mar 10 '18 at 15:08
  • Thanks. It builds correctly now, and appears that it is attempting NTLM, but produces a similar error: `The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'Negotiate, NTLM'`, which is the same error I get if if I change the `ClientCredentialType` to `Ntlm` and use my original technique. Maybe something just plain broken in the .NET Core implementation of NTLM (for non-Windows)(?) – Troy Mar 10 '18 at 17:20
  • Thanks for info on the bug report. Hopefully that'll be fixed soon. Regarding "you should try to use another type of authentication", the only other type available with this service is "Negotiate" (Kerberos?)... If you have any experience getting that working with a SOAP service, any pointers you have would be appreciated. Alternatively, since the bug is triggered when there is more than one auth header (according to the article), I wonder if there might be a way to programmatically intercept that and strip out one of the "Negotiate" header before the client code has a chance to bork out(?) – Troy Mar 13 '18 at 00:13
  • @Troy what I meant is maybe have other type of authentication enabled server side and used that from Linux. Never tried to do Kerberos from Linux. If you want to intercept the headers, it would mean like doing your own custom http binding which is similar to fix the bug. You can try the preview of 2.1 or just extract the bug fix. After all it's on github. By looking on the history of the files, you should be able to pinpoint the changes. – Fab Mar 13 '18 at 03:09
  • The 2.1 changes haven’t been made yet (according to the issue tracker). The fix is just _planned_ for 2.1. I’ll have to find my own way around it for now (unless they get to it in the next few days). Unfortunately, I’m not super familiar with .NET yet... but knowing that the double auth header is the trigger certainly helps. Thanks! – Troy Mar 13 '18 at 03:57
  • well.. two years later it still does not work: https://stackoverflow.com/questions/60296237/windows-authentication-in-linux-docker-container In .net core documentation they say NTLM is not supported in kestrel, however some says that it works with .net 5 which I was not able to confirm. They say that .net core 3+ supports negotiate, but our AD seems to be outdated (win 2008 r2) so no luck for me either.. – Scholtz Mar 17 '20 at 14:14
1

It is important to know how authentication works differently in Windows/Console app VS Web application.

Answers to your question to skip Negotiate (From Server): Go to IIS --> Go to site/application --> Select Authentication (Double Click on that)--> You will see options here --> Under Windows authentication (if this is enabled) then --> click on Provider in right side action pan.

Here you can move up down/remove "Negotiate" options.

  • Unfortunately, it's a third-party service. I don't have an option to change the server side. – Troy Mar 13 '18 at 22:27