Skip to content

Kerberos (SPNEGO) support for HTTP#3941

Merged
bk2204 merged 6 commits intogit-lfs:masterfrom
bk2204:kerberos
Jan 3, 2020
Merged

Kerberos (SPNEGO) support for HTTP#3941
bk2204 merged 6 commits intogit-lfs:masterfrom
bk2204:kerberos

Conversation

@bk2204
Copy link
Member

@bk2204 bk2204 commented Dec 4, 2019

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

@bk2204 bk2204 requested a review from a team December 6, 2019 18:42
@bk2204 bk2204 marked this pull request as ready for review December 6, 2019 18:42
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.
Copy link
Member

@chrisd8088 chrisd8088 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fantastic ... thank you!

@bk2204 bk2204 merged commit d37bbfe into git-lfs:master Jan 3, 2020
@bk2204 bk2204 deleted the kerberos branch January 3, 2020 14:51
@itsho
Copy link

itsho commented Jan 8, 2020

This will be extremely useful. when is the next release planned for?
thanks in advance! 😃

@bk2204
Copy link
Member Author

bk2204 commented Jan 8, 2020

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.

@itsho
Copy link

itsho commented Jan 12, 2020

I've compiled the latest version and tested it with our local build machine.

  1. I'm still getting HTTP_1_1_REQUIRED
  2. the Domain User got locked. 😕

log summary:

git-lfs/2.9.3 (GitHub; windows amd64; go 1.13.5; git 770719d)
Receiving objects: 100% .............. done.
Resolving deltas: 100% .............., done.
git -c http.https://-------------.extraheader="AUTHORIZATION: bearer ********" lfs fetch origin ..............................bd
fetch: Fetching reference ........................bd
LFS: Get https://................/info/lfs/objects/...........................6f: stream error: stream ID 3205; HTTP_1_1_REQUIRED
error: failed to fetch some objects from 'https://................/_git/ufed.git/info/lfs'
##[command]git lfs logs last
No logs to show
Error: Git lfs fetch failed with exit code: 2. Git lfs logs returned with exit code: 0.

@bk2204
Copy link
Member Author

bk2204 commented Jan 13, 2020

It's known that you have to set http.version to HTTP/1.1 if you use Kerberos or NTLM with IIS; that isn't changing.

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 GIT_TRACE=1 GIT_TRANSFER_TRACE=1 GIT_CURL_VERBOSE=1 with at least the first 12 characters of the Base64-encoded Negotiate responses so I can look into this?

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it right that you have v7 when go-spnego is using v5.3.0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

chrisd8088 added a commit to manturovDan/git-lfs that referenced this pull request Mar 5, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

git-lfs does not support negotiate authentication

4 participants