Fix Kerberos/NTLM for multiple domain/realm environments in Linux#36329
Fix Kerberos/NTLM for multiple domain/realm environments in Linux#36329davidsh merged 2 commits intodotnet:masterfrom
Conversation
0b989eb to
28b8d58
Compare
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
|
/azp run corefx-outerloop-linux |
|
Azure Pipelines successfully started running 1 pipeline(s). |
| // Convert any "SERVICE/HOST" style of targetName to use "SERVICE@HOST" style. | ||
| // This is because the System.Net.Security.Native GSS-API layer uses | ||
| // GSS_C_NT_HOSTBASED_SERVICE format for targetName. | ||
| _targetName = SafeGssNameHandle.CreateTarget(targetName.Replace('/', '@')); |
There was a problem hiding this comment.
Is there any situation where / might appear where it shouldn't be replaced? e.g. could / be escaped somehow?
There was a problem hiding this comment.
No. The formats for SPN are very specific. Windows always uses SERVICE/HOST for example for Service Principal Names. And there can't be embedded slashes in those. It would be a malformed name and generate errors anyways.
| retFlags, | ||
| NULL); | ||
|
|
||
| if (isNtlm) |
There was a problem hiding this comment.
Seems like this could be:
*isNtlmUsed = (isNtlm || majorStatus != GSS_S_COMPLETE || gss_oid_equal(outmech, krbMech) == 0) ? 1 : 0;?
There was a problem hiding this comment.
This is C code and not C#. Does the tertiary operation work in C? :)
There was a problem hiding this comment.
Yes, C has a ternary operator.
There was a problem hiding this comment.
Thank you! I didn't realize that. I'll make the changes you suggested.
|
/azp run corefx-outerloop-linux |
|
Azure Pipelines successfully started running 1 pipeline(s). |
| { | ||
| if (IsCurlHandler) | ||
| { | ||
| throw new SkipTestException("Skipping test on CurlHandler (libCurl)"); |
There was a problem hiding this comment.
I haven't seen this before. Is there a new pattern for skipping tests?
There was a problem hiding this comment.
Yes. It requires ConditionalFact or ConditionalTheory even if you don't specify a condition. And it requires another using statement as well.
using Microsoft.DotNet.XUnitExtensions;We've started to use this pattern in our updated tests.
There was a problem hiding this comment.
And using this new pattern shows up better in the test logs because it will say that it skipped the test and print out the reason why.
rmkerr
left a comment
There was a problem hiding this comment.
Removing code and increasing functionality at the same time? I'm a huge fan of that. LGTM.
This PR is a follow-up to PR dotnet#36329. In that previous PR, I changed to use the GSS_C_NT_HOSTBASED_SERVICE format for the SPN. That requires using a '@' separator character instead of a "/". I had assumed since System.Data.SqlClient was including the source files from Common for SafeDeleteNegoContext.cs that it would have the corresponding change to use the proper separator character. However, it appears that the file was only included to get the project building. It was using a separate file to calculate the SPN. The customer requiring these fixes reported that Kerberos was working properly now for HttpClient and NegotiateStream. But SqlClient was still broken. This PR completes the fix so that SqlClient will work properly with Kerberos especially in multiple domain/realm environments. This fix was manually tested in the enterprise scenario test lab.
This PR is a follow-up to PR #36329. In that previous PR, I changed to use the GSS_C_NT_HOSTBASED_SERVICE format for the SPN. That requires using a '@' separator character instead of a "/". I had assumed since System.Data.SqlClient was including the source files from Common for SafeDeleteNegoContext.cs that it would have the corresponding change to use the proper separator character. However, it appears that the file was only included to get the project building. It was using a separate file to calculate the SPN. The customer requiring these fixes reported that Kerberos was working properly now for HttpClient and NegotiateStream. But SqlClient was still broken. This PR completes the fix so that SqlClient will work properly with Kerberos especially in multiple domain/realm environments. This fix was manually tested in the enterprise scenario test lab.
This PR ports some important Kerberos auth fixes from the 3.0 to 2.1 LTS branch. These fixes help enterprise customers that have complex Kerberos authentication scenarios that involve cross Windows (Active Directory) and Linux (Kerberos) domains/realms. These fixes are from PRs: * dotnet#38465 - Use 'Host' header when calculating SPN for Kerberos auth * dotnet#38377 - Use GSS_C_NT_HOSTBASED_SERVICE format for Linux Kerberos SPN and are related to issue dotnet#36329.
This PR ports some important Kerberos auth fixes from the 3.0 to 2.1 LTS branch. These fixes help enterprise customers that have complex Kerberos authentication scenarios that involve cross Windows (Active Directory) and Linux (Kerberos) domains/realms. These fixes are from PRs: * #38465 - Use 'Host' header when calculating SPN for Kerberos auth * #38377 - Use GSS_C_NT_HOSTBASED_SERVICE format for Linux Kerberos SPN and are related to issue #36329.
* Update BuildTools to rc1-04230-01 * Port Kerberos auth fixes to 2.1 branch (#40109) This PR ports some important Kerberos auth fixes from the 3.0 to 2.1 LTS branch. These fixes help enterprise customers that have complex Kerberos authentication scenarios that involve cross Windows (Active Directory) and Linux (Kerberos) domains/realms. These fixes are from PRs: * #38465 - Use 'Host' header when calculating SPN for Kerberos auth * #38377 - Use GSS_C_NT_HOSTBASED_SERVICE format for Linux Kerberos SPN and are related to issue #36329.
…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 is a follow-up to PR dotnet/corefx#36329. In that previous PR, I changed to use the GSS_C_NT_HOSTBASED_SERVICE format for the SPN. That requires using a '@' separator character instead of a "/". I had assumed since System.Data.SqlClient was including the source files from Common for SafeDeleteNegoContext.cs that it would have the corresponding change to use the proper separator character. However, it appears that the file was only included to get the project building. It was using a separate file to calculate the SPN. The customer requiring these fixes reported that Kerberos was working properly now for HttpClient and NegotiateStream. But SqlClient was still broken. This PR completes the fix so that SqlClient will work properly with Kerberos especially in multiple domain/realm environments. This fix was manually tested in the enterprise scenario test lab. Commit migrated from dotnet/corefx@78c4c8b
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 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:
Define standalone server remote endpoint: