Fix Negotiate/SPNEGO Kerberos to NTLM fallback on Linux#35383
Fix Negotiate/SPNEGO Kerberos to NTLM fallback on Linux#35383davidsh merged 3 commits intodotnet:masterfrom
Conversation
This PR adds support to our Linux gssapi layer so that we properly handle the Negotiate protocol (SPNEGO) being able to to fall back from Kerberos to NTLM. Windows Negotiate SSPI implements the SPNEGO protocol. However, it has built-in error handling for dealing with quick fallback from Kerberos to NTLM in error cases such as where the client is not on a domain/Kerberos realm, the client is using a local credential, the client is talking to a non-domain server, etc. However, the Linux implementation of SPNEGO doesn't handle those error cases very well. So, I added the proper retry logic when generating the initial context token. Now, we will be able to fall back from SPNEGO-wrapped Kerberos to SPNEGO-wrapped NTLM protocol blobs. A similar bug exists in libcurl which is why Curl and CurlHandler are unable to connect to Negotiate servers when not part of the Kerberos realm. I am considering proposing my fixes to the libcurl repo as well. I added more tests to support this PR and did manual testing. I added some additional EventSource tracing as well. Contributes to #34878
|
/azp run corefx-outerloop-linux |
|
No pipelines are associated with this pull request. |
src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs
Outdated
Show resolved
Hide resolved
src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs
Outdated
Show resolved
Hide resolved
|
/azp run corefx-outerloop-linux |
|
No pipelines are associated with this pull request. |
|
@davidsh this is going to sound like a weird suggestion but try doing one pipeline trigger per comment. |
|
/azp run corefx-outerloop-linux |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run corefx-outerloop-windows |
|
/azp run corefx-outerloop-osx |
|
Azure Pipelines successfully started running 1 pipeline(s). |
1 similar comment
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Ugh. That's frustrating. I learned from this PR that the pipelines trigger considers everything after |
|
@vcsjones Thx for the suggestion! I'm going to be talking to the Infrastructure team about this to make it better. |
|
@vcsjones please don't forget to ping me if you have any feedback to bring it over to azure devops folks to make this experience better |
While debugging some Linux enterprise auth (Negotiate/NTLM) scenarios, I discoverd that the logging I added in PR dotnet#35383 wasn't working. This was due to not passing in a 'null' value for the context object for NetEventSource.Info. It was using the string object as the context object and not logging the string data. As part of fixing that I optimized some code for remembering what auth package (NTLM or SPNEGO) is used.
While debugging some Linux enterprise auth (Negotiate/NTLM) scenarios, I discoverd that the logging I added in PR dotnet#35383 wasn't working. This was due to not passing in a 'null' value for the context object for NetEventSource.Info. It was using the string object as the context object and not logging the string data. As part of fixing that I optimized some code for remembering what auth package (NTLM or SPNEGO) is used.
While debugging some Linux enterprise auth (Negotiate/NTLM) scenarios, I discovered that the logging I added in PR #35383 wasn't working. This was due to not passing in a 'null' value for the context object for NetEventSource.Info. It was using the string object as the context object and not logging the string data. As part of fixing that I optimized some code for remembering what auth package (NTLM or SPNEGO) is used.
While debugging some Linux enterprise auth (Negotiate/NTLM) scenarios, I discovered that the logging I added in PR dotnet#35383 wasn't working. This was due to not passing in a 'null' value for the context object for NetEventSource.Info. It was using the string object as the context object and not logging the string data. As part of fixing that I optimized some code for remembering what auth package (NTLM or SPNEGO) is used.
|
Are there plans to backport this into the 2.2 (or 2.1) series? |
This is a fix among several that I've already made addressing Enterprise Authentication scenarios. We are considering backporting them as a group to 2.1/2.2. But the decision hasn't been made yet. We are waiting to finish a few more fixes in master branch (.NET Core 3.0) before considering this. |
|
For porting to 2.1/2.2 we would need a very good and strong business case - number of customers who are blocked without the ports and who cannot upgrade to 3.0 from good reasons. |
This PR addresses some issues reported by a customer (not thru GitHub). They noticed that multiple domain scenarios were working in .NET Core 2.0 but broke in .NET Core 2.1 on Linux While the previous PR dotnet#35383 solved the Negotiate Kerberos to NTLM fallback issue, it added more complexity than necessary. The retry logic I added wasn't really necessary because the original code that used GSS_KRB5_NT_PRINCIPAL_NAME format for the target name was wrong. That logic only works for pure Kerberos environments and doesn't handle domain or realm referrals. So, it only handles the default Kerberos realm on the the single Linux client. In addition, using GSS_KRB5_NT_PRINCIPAL_NAME defeats the logic of the SPNEGO mechanism. That is why I originally needed to add the retry logic using GSS_C_NT_HOSTBASED_SERVICE format for the target name. The multiple domain/realm scenario worked in .NET Core 2.0 because it used CurlHandler. And libcurl always uses GSS_C_NT_HOSTBASED_SERVICE format for target name. This PR reworks the logic to use the GSS_C_NT_HOSTBASED_SERVICE format. It also removes the now unneeded retry logic. I tested this against Windows and Linux as well as pure Kerberos and Kerberos to NTLM fallback (using SPNEGO). I added more tests. These tests are currently part of the enterprise scenario tests we are building. They are activated via environment variables. By definining all of the environment variables below, I am able to run the System.Net.Security and System.Net.Http enterprise-scenario tests. Both SocketsHttpHandler in System.Net.Http and NegotiateStream in System.Net.Security use the same common GSS-API logic in CoreFx. Define domain-joined server remote endpoint: * COREFX_NET_SECURITY_NEGOSERVERURI * COREFX_DOMAINJOINED_HTTPHOST * COREFX_NET_AD_DOMAINNAME * COREFX_NET_AD_PASSWORD * COREFX_NET_AD_USERNAME Define standalone server remote endpoint: * COREFX_NET_SERVER_PASSWORD * COREFX_NET_SERVER_USERNAME * COREFX_WINDOWSSERVER_HTTPHOST
This PR addresses some issues reported by a customer (not thru GitHub). They noticed that multiple domain scenarios were working in .NET Core 2.0 but broke in .NET Core 2.1 on Linux While the previous PR dotnet#35383 solved the Negotiate Kerberos to NTLM fallback issue, it added more complexity than necessary. The retry logic I added wasn't really necessary because the original code that used GSS_KRB5_NT_PRINCIPAL_NAME format for the target name was wrong. That logic only works for pure Kerberos environments and doesn't handle domain or realm referrals. So, it only handles the default Kerberos realm on the the single Linux client. In addition, using GSS_KRB5_NT_PRINCIPAL_NAME defeats the logic of the SPNEGO mechanism. That is why I originally needed to add the retry logic using GSS_C_NT_HOSTBASED_SERVICE format for the target name. The multiple domain/realm scenario worked in .NET Core 2.0 because it used CurlHandler. And libcurl always uses GSS_C_NT_HOSTBASED_SERVICE format for target name. This PR reworks the logic to use the GSS_C_NT_HOSTBASED_SERVICE format. It also removes the now unneeded retry logic. I tested this against Windows and Linux as well as pure Kerberos and Kerberos to NTLM fallback (using SPNEGO). I added more tests. These tests are currently part of the enterprise scenario tests we are building. They are activated via environment variables. By definining all of the environment variables below, I am able to run the System.Net.Security and System.Net.Http enterprise-scenario tests. Both SocketsHttpHandler in System.Net.Http and NegotiateStream in System.Net.Security use the same common GSS-API logic in CoreFx. Define domain-joined server remote endpoint: * COREFX_NET_SECURITY_NEGOSERVERURI * COREFX_DOMAINJOINED_HTTPHOST * COREFX_NET_AD_DOMAINNAME * COREFX_NET_AD_PASSWORD * COREFX_NET_AD_USERNAME Define standalone server remote endpoint: * COREFX_NET_SERVER_PASSWORD * COREFX_NET_SERVER_USERNAME * COREFX_WINDOWSSERVER_HTTPHOST
This PR addresses some issues reported by a customer (not thru GitHub). They noticed that multiple domain scenarios were working in .NET Core 2.0 but broke in .NET Core 2.1 on Linux While the previous PR dotnet#35383 solved the Negotiate Kerberos to NTLM fallback issue, it added more complexity than necessary. The retry logic I added wasn't really necessary because the original code that used GSS_KRB5_NT_PRINCIPAL_NAME format for the target name was wrong. That logic only works for pure Kerberos environments and doesn't handle domain or realm referrals. So, it only handles the default Kerberos realm on the the single Linux client. In addition, using GSS_KRB5_NT_PRINCIPAL_NAME defeats the logic of the SPNEGO mechanism. That is why I originally needed to add the retry logic using GSS_C_NT_HOSTBASED_SERVICE format for the target name. The multiple domain/realm scenario worked in .NET Core 2.0 because it used CurlHandler. And libcurl always uses GSS_C_NT_HOSTBASED_SERVICE format for target name. This PR reworks the logic to use the GSS_C_NT_HOSTBASED_SERVICE format. It also removes the now unneeded retry logic. I tested this against Windows and Linux as well as pure Kerberos and Kerberos to NTLM fallback (using SPNEGO). I added more tests. These tests are currently part of the enterprise scenario tests we are building. They are activated via environment variables. By definining all of the environment variables below, I am able to run the System.Net.Security and System.Net.Http enterprise-scenario tests. Both SocketsHttpHandler in System.Net.Http and NegotiateStream in System.Net.Security use the same common GSS-API logic in CoreFx. Define domain-joined server remote endpoint: * COREFX_NET_SECURITY_NEGOSERVERURI * COREFX_DOMAINJOINED_HTTPHOST * COREFX_NET_AD_DOMAINNAME * COREFX_NET_AD_PASSWORD * COREFX_NET_AD_USERNAME Define standalone server remote endpoint: * COREFX_NET_SERVER_PASSWORD * COREFX_NET_SERVER_USERNAME * COREFX_WINDOWSSERVER_HTTPHOST
…6329) This PR addresses some issues reported by a customer (not thru GitHub). They noticed that multiple domain scenarios were working in .NET Core 2.0 but broke in .NET Core 2.1 on Linux. While the previous PR #35383 solved the Negotiate Kerberos to NTLM fallback issue, it added more complexity than necessary. The retry logic I added wasn't really necessary because the original code that used GSS_KRB5_NT_PRINCIPAL_NAME format for the target name was wrong. That logic only works for pure Kerberos environments and doesn't handle domain or realm referrals. So, it only handles the default Kerberos realm on the the single Linux client. In addition, using GSS_KRB5_NT_PRINCIPAL_NAME defeats the logic of the SPNEGO mechanism. That is why I originally needed to add the retry logic using GSS_C_NT_HOSTBASED_SERVICE format for the target name. The multiple domain/realm scenario worked in .NET Core 2.0 because it used CurlHandler. And libcurl always uses GSS_C_NT_HOSTBASED_SERVICE format for target name. This PR reworks the logic to use the GSS_C_NT_HOSTBASED_SERVICE format. It also removes the now unneeded retry logic. I tested this against Windows and Linux as well as pure Kerberos and Kerberos to NTLM fallback (using SPNEGO). I added more tests. These tests are currently part of the enterprise scenario tests we are building. They are activated via environment variables. By defining all of the environment variables below, I am able to run the System.Net.Security and System.Net.Http enterprise-scenario tests. Both SocketsHttpHandler in System.Net.Http and NegotiateStream in System.Net.Security use the same common GSS-API logic in CoreFx. Define domain-joined server remote endpoint: * COREFX_NET_SECURITY_NEGOSERVERURI * COREFX_DOMAINJOINED_HTTPHOST * COREFX_NET_AD_DOMAINNAME * COREFX_NET_AD_PASSWORD * COREFX_NET_AD_USERNAME Define standalone server remote endpoint: * COREFX_WINDOWSSERVER_HTTPHOST * COREFX_NET_SERVER_PASSWORD * COREFX_NET_SERVER_USERNAME
…x#35383) This PR adds support to our Linux gssapi layer so that we properly handle the Negotiate protocol (SPNEGO) being able to to fall back from Kerberos to NTLM. Windows Negotiate SSPI implements the SPNEGO protocol. However, it has built-in error handling for dealing with quick fallback from Kerberos to NTLM in error cases such as where the client is not on a domain/Kerberos realm, the client is using a local credential, the client is talking to a non-domain server, etc. However, the Linux implementation of SPNEGO doesn't handle those error cases very well. So, I added the proper retry logic when generating the initial context token. Now, we will be able to fall back from SPNEGO-wrapped Kerberos to SPNEGO-wrapped NTLM protocol blobs. A similar bug exists in libcurl which is why Curl and CurlHandler are unable to connect to Negotiate servers when not part of the Kerberos realm. I am considering proposing my fixes to the libcurl repo as well. I added more tests to support this PR and did manual testing. I added some additional EventSource tracing as well. Contributes to dotnet/corefx#34878 Commit migrated from dotnet/corefx@1fd3ba1
…5918) While debugging some Linux enterprise auth (Negotiate/NTLM) scenarios, I discovered that the logging I added in PR dotnet/corefx#35383 wasn't working. This was due to not passing in a 'null' value for the context object for NetEventSource.Info. It was using the string object as the context object and not logging the string data. As part of fixing that I optimized some code for remembering what auth package (NTLM or SPNEGO) is used. Commit migrated from dotnet/corefx@21db29a
…tnet/corefx#36329) This PR addresses some issues reported by a customer (not thru GitHub). They noticed that multiple domain scenarios were working in .NET Core 2.0 but broke in .NET Core 2.1 on Linux. While the previous PR dotnet/corefx#35383 solved the Negotiate Kerberos to NTLM fallback issue, it added more complexity than necessary. The retry logic I added wasn't really necessary because the original code that used GSS_KRB5_NT_PRINCIPAL_NAME format for the target name was wrong. That logic only works for pure Kerberos environments and doesn't handle domain or realm referrals. So, it only handles the default Kerberos realm on the the single Linux client. In addition, using GSS_KRB5_NT_PRINCIPAL_NAME defeats the logic of the SPNEGO mechanism. That is why I originally needed to add the retry logic using GSS_C_NT_HOSTBASED_SERVICE format for the target name. The multiple domain/realm scenario worked in .NET Core 2.0 because it used CurlHandler. And libcurl always uses GSS_C_NT_HOSTBASED_SERVICE format for target name. This PR reworks the logic to use the GSS_C_NT_HOSTBASED_SERVICE format. It also removes the now unneeded retry logic. I tested this against Windows and Linux as well as pure Kerberos and Kerberos to NTLM fallback (using SPNEGO). I added more tests. These tests are currently part of the enterprise scenario tests we are building. They are activated via environment variables. By defining all of the environment variables below, I am able to run the System.Net.Security and System.Net.Http enterprise-scenario tests. Both SocketsHttpHandler in System.Net.Http and NegotiateStream in System.Net.Security use the same common GSS-API logic in CoreFx. Define domain-joined server remote endpoint: * COREFX_NET_SECURITY_NEGOSERVERURI * COREFX_DOMAINJOINED_HTTPHOST * COREFX_NET_AD_DOMAINNAME * COREFX_NET_AD_PASSWORD * COREFX_NET_AD_USERNAME Define standalone server remote endpoint: * COREFX_WINDOWSSERVER_HTTPHOST * COREFX_NET_SERVER_PASSWORD * COREFX_NET_SERVER_USERNAME Commit migrated from dotnet/corefx@658ec73
This PR adds support to our Linux gssapi layer so that we properly handle the Negotiate
protocol (SPNEGO) being able to to fall back from Kerberos to NTLM.
Windows Negotiate SSPI implements the SPNEGO protocol. However, it has built-in error
handling for dealing with quick fallback from Kerberos to NTLM in error cases such as where
the client is not on a domain/Kerberos realm, the client is using a local credential, the
client is talking to a non-domain server, etc.
However, the Linux implementation of SPNEGO doesn't handle those error cases very well.
So, I added the proper retry logic when generating the initial context token. Now, we will
be able to fall back from SPNEGO-wrapped Kerberos to SPNEGO-wrapped NTLM protocol blobs.
A similar bug exists in libcurl which is why Curl and CurlHandler are unable to connect to
Negotiate servers when not part of the Kerberos realm. I am considering proposing my fixes
to the libcurl repo as well.
I added more tests to support this PR and did manual testing. I added some additional
EventSource tracing as well.
Contributes to #34878