wine-mono icon indicating copy to clipboard operation
wine-mono copied to clipboard

WebClient / WebRequest can't use Negotiate (Kerberos) authentication

Open IncubusRK opened this issue 3 years ago • 15 comments

When try next simple test, I get data on Windows, and WebException under wine-mono.

var request = (HttpWebRequest)WebRequest.Create("KERBEROS_TEST_URL");
request.Credentials = CredentialCache.DefaultCredentials;
request.UseDefaultCredentials = true;
using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = new StreamReader(response.GetResponseStream()))
    Console.WriteLine("Response first line: {0}", responseStream.ReadLine());

I check negotiate auth in wine by install windows version of Firefox, it's work correct.

IncubusRK avatar Dec 14 '21 07:12 IncubusRK

I also install dotnet 4.6.1 by using "winetricks dotnet461", and negotiate sample from first post also works fine.

sample-source.zip

IncubusRK avatar Dec 14 '21 07:12 IncubusRK

Maybe importing System.Net.Security namespace from corefx can fix this. NegotiateStream.cs from mono is only throwing NotImplementedException.

IncubusRK avatar Dec 15 '21 06:12 IncubusRK

The corefx version of this doesn't seem to be complete. It references a method called InitializeStreamPart that I can't find.

Edit: Never mind, it's in InternalNegotiateStream.cs, guess I'll keep trying.

madewokherd avatar Jan 04 '22 20:01 madewokherd

Looks like this will require implementations of the AssociatedName, Spn, IsNTLM, IsMutualAuthFlag, IsConfidentialityFlag, IsIntegrityFlag, IsDelegationFlag, Encrypt, and Decrypt members of the NTAuthentication class in Mono.

madewokherd avatar Jan 04 '22 20:01 madewokherd

OK, turns out Mono doesn't have an implementation of that either, I was just confused by their modification of the one in referencesource. So we can import that from corefx too.

Surprisingly, with a few imports from corefx, it builds, but I don't have a way to test it. I'll make a PR with the changes.

madewokherd avatar Jan 04 '22 21:01 madewokherd

I make quick test, importing NegotiateStream is not enough. I try to make detailed test on next week. Maybe another part of System.Net.Security also required...

IncubusRK avatar Jan 05 '22 14:01 IncubusRK

Calling HttpWebRequest.GetResponse() in dotnet automatically add "Authorization: Negotiate ..." to HttpWebRequest.Headers. Wine-mono don't do that even after import NegotiateStream from corefx.

IncubusRK avatar Jan 11 '22 11:01 IncubusRK

It could be that there's some special treatment elsewhere in corefx that we need to port to the Mono class libraries.

madewokherd avatar Jan 11 '22 17:01 madewokherd

I'm having trouble figuring out how the Authorization header is supposed to get set, in either Mono classlibs or corefx.

madewokherd avatar Jan 11 '22 18:01 madewokherd

So, if I'm understanding this correctly, Negotiate is a wire protocol for authentication, and by itself is not based on HTTP. NegotiateStream implements the wire protocol and none of the HTTP parts. For this to work in HTTP requests we still need something to connect the HTTP bits to the lower level implementation in NegotiateStream.

madewokherd avatar Jan 11 '22 18:01 madewokherd

On corefx's HttpWebRequest, this appears to work based on winhttp.dll and not use NegotiateStream at all. I don't think switching over to this implementation is feasible, last time I tried to do something similar (to try to get crypt32-based certificate management) I found too many interdepedencies.

On Mono's HttpWebRequest, this works based on the AuthenticationManager class, for which Mono has registered builtin IAuthenticationModule classes for Basic, Digest, and NTLM authentication.

So, I think we need an IAuthenticationModule class for Negotiate, and such a thing doesn't exist yet. NegotiateStream may help, if it actually works (I don't currently have a way to test it, and I'm still suspicious of it). I don't understand how Negotiate works, so I don't know how hard that is, but for now it doesn't seem worth it for me to work on this, sorry.

madewokherd avatar Jan 11 '22 19:01 madewokherd

I believe that the mechanism should be similar to the one in tests NegotiateStreamKerberosTest.cs Unfortunately in practice ClientStream turns out to be closed before calling AuthenticateAsClientasync

IncubusRK avatar Jan 14 '22 11:01 IncubusRK

Based on https://www.ietf.org/rfc/rfc4559.txt it seems like this communicates through repeated HTTP requests with different headers. NegoiateStream seems to use GSS-SPNEGO? Anyway, I don't think it's even helpful for this.

madewokherd avatar Jan 14 '22 18:01 madewokherd

Hm, or maybe there needs to be a translation between HTTP header data and stream data? I still don't really get this.

madewokherd avatar Jan 14 '22 18:01 madewokherd

On corefx's HttpWebRequest, this appears to work based on winhttp.dll and not use NegotiateStream at all.

I try to run samples with WINEDEBUG=+kerberos,secur32,schannel,wininet,winhttp and I do not see the any calls of functions from these libraries...

IncubusRK avatar Aug 22 '22 07:08 IncubusRK