runtime: SocketsHttpHandler: NTLM auth does not work by default on Unix

HttpClient with credentials explicitly set. SocketHttpHandler throws on NTLM authentication requested by server:

System.ComponentModel.Win32Exception (0x80090020): GSSAPI operation failed with error - An invalid status code was supplied (Unknown error).
  at System.Net.Security.NegotiateStreamPal.AcquireCredentialsHandle(String package, Boolean isServer, NetworkCredential credential) in /home/build/github/corefx/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs:line 316
  at System.Net.NTAuthentication.Initialize(Boolean isServer, String package, NetworkCredential credential, String spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) in /home/build/github/corefx/src/Common/src/System/Net/NTAuthentication.Common.cs:line 128
  at System.Net.NTAuthentication..ctor(Boolean isServer, String package, NetworkCredential credential, String spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding) in /home/build/github/corefx/src/Common/src/System/Net/NTAuthentication.Common.cs:line 98
  at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, CancellationToken cancellationToken) in /home/build/github/corefx/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs:line 61
  at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken) in /home/build/github/corefx/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 283
  at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken) in /home/build/github/corefx/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs:line 204
  at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts) in /home/build/github/corefx/src/Sys

Workarounds:

  1. Install package called gss-ntlmssp (plugin into MIT Kerberos GSSAPI layer)
  2. Install Heimdal (alternative Kerberos implementation with NTLM support): https://www.h5l.org/manual/heimdal-1-5-branch/ntlm/

One of the options installed is sufficient to make SocketHttpHandler work for NTLM without any additional changes to CoreFX or the app.

Details: .NET Core 2.0 / 2.1 with libcurl works fine. This is because curl has it’s own implementation but SocketHttpHandler depends on authentication code shared with NegotiateStream class.

The shared authentication depends on GSSAPI and that is typically provided by MIT kerberos. (this is also true for 2.1.300 preview docker images) It does not have ability to do NTLM.

This is follow up on dotnet/runtime#25370 and dotnet/runtime#25368. This may be also related to https://github.com/dotnet/wcf/issues/943

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 11
  • Comments: 27 (11 by maintainers)

Most upvoted comments

@ncsurfus the AppContext.SetSwitch workaround you suggested worked perfectly and saved our project a lot of time. Thanks.

I am using microsoft/dotnet:2.1-aspnetcore-runtime image, and I did install gss-ntlmssp. It makes the GSSAPI operation failed error go away.

However, then I get System.PlatformNotSupportedException: No support for channel binding on operating systems other than Windows.

Is there another package I’m missing?

Hi folks,

I having some issue getting the workaround working.

Im am using the following to build a docker image.

#Build Image
FROM microsoft/dotnet:2.1.403-sdk AS build

# Make a working dir
WORKDIR /app
# Copy from local filesystem into working dir
COPY . .
# Publish
RUN dotnet publish Src/myapp/myapp.csproj -c Release -o /publish

#Runtime Image
FROM microsoft/dotnet:2.1.5-runtime AS final

# Workaround as per https://github.com/dotnet/corefx/issues/28961
RUN apt-get update
RUN apt-get -y install gss-ntlmssp

# Make a working dir
WORKDIR /app
# Copy publish output from last image
COPY --from=build /publish .
# Set Entry Point for Container
ENTRYPOINT ["dotnet", "myapp.dll"]

When I run this overriding the entrypoint i can confirm gss-ntlmssp is installed by attempting to install it again. It tells me the latest is installed.

I still get this thrown tho.

GSSAPI operation failed with error - An invalid status code was supplied (Invalid value in argument).
System.ComponentModel.Win32Exception (0x80090020): GSSAPI operation failed with error - An invalid status code was supplied (Invalid value in argument).
   at System.Net.NTAuthentication.GetOutgoingBlob(Byte[] incomingBlob, Boolean throwOnError, SecurityStatusPal& statusCode)
   at System.Net.NTAuthentication.GetOutgoingBlob(String incomingBlob)
   at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

Adding the following stops the error occurring but then my request returns a 401.

AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

Running the exact same code locally on my windows 10 box works perfectly.

I think the problem is authenticating with servers that support NTLM Extended Protection (Channel Binding). It binds the NTLM auth to a specific TLS session to prevent authenticating through a Proxy/MITM. I think there is a flag that gets set from the server’s NTLM Challenge Message that specifies it supports channel binding… however in the case of IIS, you can support extended protection, but not require it. SocketsHttpHandler doesn’t try to continue the authentication (as if it were unaware of channel binding). Having a consistent experience between Linux and Windows would be a huge bonus!

We seem to be getting this error all the time for any https site using NTLM even if Extended Protection (i.e. “channel binding”) is OFF.

Unhandled Exception: System.PlatformNotSupportedException: No support for channel binding on operating systems other than Windows.
   at System.Net.Security.NegotiateStreamPal.InitializeSecurityContext(SafeFreeCredentials credentialsHandle, SafeDeleteContext& securityContext, String spn, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ContextFlagsPal& contextFlags)
   at System.Net.NTAuthentication.GetOutgoingBlob(Byte[] incomingBlob, Boolean throwOnError, SecurityStatusPal& statusCode)
   at System.Net.NTAuthentication.GetOutgoingBlob(String incomingBlob)
   at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at httptest.Program.Main(String[] args) in /home/root/httptest/Program.cs:line 18

So, at a minimum, this should get fixed to at least support NTLM connections where channel binding is Off or Accept’d.

image

I’d also like to note that switching back to the libcurl implementation AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); is what I did as a work-around to get NTLM working properly on Linux… hopefully this can be fixed/implemented.

Yes, it would be nice to have specific exception with reason “NTLM is not supported by the underlying OS” with permalink to article with potential workarounds. Assuming we can detect from the GSSAPI error code that the root-cause is missing support for NTLM and nothing else.

Just adding confirmation that upgrading to dotnet 3 fixed this issue for us.

Thanks all.

After looking through this thread and investigating all the mentioned problems, I have split this issue into new issues and will be closing this issue.

New issues:

  • Incorrect exception message shown during NTLM authentication dotnet/corefx#34877
  • Negotiate to NTLM authentication fallback not working dotnet/corefx#34878
  • HTTPS and NTLM authentication throw PlatformNotSupportedException dotnet/corefx#34879

@AlexanderLeonov we had issues with both NTLM and then with HTTPS connections in .NET Core 2.1 For the NTLM issue we just felled back to using LibCurl implementation of HttpClient using the AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);. Then the NTLM worked fine but we had issues with HTTPS requests to reCaptcha service. THe app was crashing wt Segmentation Fault. We used self-contained mode for the app. The problem was that in our environment (Ubuntu 14.04) the System.Net.Http.Native.dll was linked against libcurl.1.0.0 and our application during run-time was loading the libcurl.1.0.2. Our workaround was to copy libcurl.1.0.0 in our app folder and setting an environmental variable that was adding that folder to the library lookup path.

@ncsurfus @greggbjensen I’m having the same issue. In my case though it is strictly tied to connection over https. It works fine if I just change url to http.

Can someone elaborate a bit on this message? What are those “channel bindings” that are not supported on linux? Is there any fix/workaround for this issue? Using http scheme is not an option in our case cause it is a connection over the internet transferring potentially sensitive information.