Kerberos (SPNEGO) support for HTTP#3941
Conversation
In the future, we're going to need to access the access-related types in the lfshttp package. To avoid an import loop, move Access and AccessMode into the creds package. Add constructors and accessors since the members are private.
We're going to want to customize the creation of the transport object in a little bit, so split it out into its own function.
In the future, we'll adjust the transport based on the access type, so cache clients based on both the host name and the access type. If it's not clear what type of access we're using, default to NoneAccess, since this will be correct for most types.
Accept an access mode and pass it down to the transport creation function.
We'll need some additional dependencies to add support for Kerberos to Git LFS. In order to support HTTP SPNEGO (Negotiate) support, add the required modules and vendor their dependencies.
Add support for Kerberos authentication using SPNEGO (Negotiate). Because NTLM is also supported by GSSAPI and can also use Negotiate, try Kerberos (which is far more secure) first, and only then fall back to NTLM. Similar to NTLM, no credentials are required, because the user has a credential storage mechanism that provides them automatically.
|
This will be extremely useful. when is the next release planned for? |
|
The next release is planned for this month. Please feel free to try it out using one of the CI artifact binaries (or one you've built yourself), especially if you're using Windows, so that if there are any problems, we can fix them before the release. |
|
I've compiled the latest version and tested it with our local build machine.
log summary:
|
|
It's known that you have to set It's interesting that it got locked, because we do fall back to NTLM if Kerberos fails for some reason. Unfortunately, we don't have a good way of knowing what kind of Negotiate authentication the remote side supports. Can you open a new issue with the output of running with |
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a | ||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d | ||
| gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect | ||
| gopkg.in/jcmturner/gokrb5.v7 v7.3.0 // indirect |
There was a problem hiding this comment.
Is it right that you have v7 when go-spnego is using v5.3.0?
There was a problem hiding this comment.
It appears that's a mistake. I think #4035 should fix that.
It perhaps snuck in before I used go-spnego and was doing things by hand. Thanks for pointing it out.
In prior commits in this PR we added several new test functions to our "lfsapi" package to verify the behaviour of the DoWithAuth() method of that package's Client structure. These new functions include the TestDoWithAuthRetryLimitExceeded() function and the TestDoWithAuthMultistageRetryLimitExceeded() function, both of which check that the DoWithAuth() method now limits the number of HTTP requests it will make if each request receives a 401 Unauthorized status code in its response. Both test functions follow a similar design as the existing TestDoWithAuthApprove() function. That older test function ends with a check of the access mode which has been cached for the endpoint URL associated with the HTTP requests made by the DoWithAuth() method, as we expect that after the first 401 status code response is received, this mode will be set to the BasicAccess mode from our "creds" package to reflect that HTTP Basic Authentication should be used with all subsequent requests. Although our new TestDoWithAuthRetryLimitExceeded() function also ends with a check of the cached access mode, this is not yet the case for the TestDoWithAuthMultistageRetryLimitExceeded() function, so we add that check now. We also take the opportunity to simplify all of the access mode assertion checks we make, which at present explicitly pass structure pointers as the receiver parameters of the Mode() method of the Access structure from our "creds" package. While this method is defined with a pointer receiver, it is not necessary to explicitly generate these pointers because Go automatically does so as a convenience feature of the language: https://go.dev/tour/methods/6 The use of explicit pointer receivers for the Mode() method calls in our test functions dates from commit 6d29072 in PR git-lfs#3941, when the Access structure was first moved into our "creds" package.
Currently, Git LFS doesn't support Kerberos; it only supports NTLM using the Negotiate authentication method. Kerberos is commonly used on Windows as part of Active Directory, as well as on Unix systems. It is well understood, and provided the standard cryptographic assumptions are met, is far more secure than NTLM.
This series introduces support for Kerberos when the remote server advertises support for the Negotiate method. Negotiate supports both Kerberos and NTLM, but the choice can only be distinguished by the messages sent, which necessarily requires an authentication attempt. Consequently, we attempt to use Kerberos, and if it fails for any reason, we fall back to NTLM. This ensures we don't break existing users.
This series works correctly on a Debian sid system against a Kerberos domain running a MIT Kerberos KDC on Debian buster. Although the series should work fine on Windows, it has not been tested there, and consequently Windows support is experimental. The number of algorithms supported by the Go Kerberos library is limited, but should support the most common and secure types (AES with HMAC-SHA-1 and AES with HMAC-SHA-2), which are also supported on Windows.
Because Kerberos requires a trusted third party (the KDC, key distribution center, or Kerberos server), there are few tests for this case, as it wouldn't be reasonable to set up an entire Kerberos infrastructure in the testsuite.
Fixes #2576