Search code examples
giteclipsetfsegitjgit

Eclipse EGit TFS Git Connection - Authentication not supported


Hi,

We are facing this dreadful issue "authentication not supported" when using egit from eclipse. I have read many articles, questions but none of them seem to solve the issue at hand.

We are using Microsoft Team Foundation Server 2015 which can provide a git repository as version control system. But authentication mechanism does not seem to work using eclipse's egit plugin. We checked using different eclipse versions from eclipse 2020-06, 2020-12, 2021-03 with different jdk setup 1.8, 11 and 15 but no success.

The cloning, push/fetch works fine with git commandline (git bash - windows) even legacy eclipse kepler is working fine without issue, but not the latest ones. The issue seems to be related to NTLM authentication. In newer versions of eclipse, egit doesn't negotiate or send NTLM token even after the server respond with WWW-Authenticate: NTLM.

Below are details for both newer and older eclipse versions, tunneled through TCP/IP Monitor for traffic capture. TFS git repository clone protocol is http even though the portal is on https.

Eclipse 2021-03

Request:

GET /tfs/xxx/_git/xxx/info/refs?service=git-upload-pack HTTP/1.1
Accept-Encoding: gzip
Pragma: no-cache
User-Agent: JGit/5.11.0.202103091610-r
Accept: application/x-git-upload-pack-advertisement, */*
Git-Protocol: version=2
Host: tfs-xxx-xx:8090
Connection: Keep-Alive

Response:

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-TFS-ProcessId: 76ec3355-4bc2-498d-ba64-xxxxxxx
X-FRAME-OPTIONS: SAMEORIGIN
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Access-Control-Allow-Methods: OPTIONS,GET,POST,PATCH,PUT,DELETE
Access-Control-Expose-Headers: ActivityId,X-TFS-Session
Access-Control-Allow-Headers: authorization
Set-Cookie: Tfs-SessionId=3b370bd6-2197-xxxxxxxxx; path=/
Set-Cookie: Tfs-SessionActive=2021-05-11T17:25:24; path=/
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
P3P: CP="CAO xxxxxxxxxxxxxxxxx"
X-Content-Type-Options: nosniff
Date: Tue, 11 May 2021 17:25:24 GMT
Content-Length: 1293

Eclipse Kepler

First Request/Response is similar to above.

Second Request:

GET /tfs/xxx/_git/xxx/info/refs?service=git-upload-pack HTTP/1.1
Accept-Encoding: gzip
Pragma: no-cache
User-Agent: JGit/3.2.0.201312181205-r
Accept: application/x-git-upload-pack-advertisement, */*
Cache-Control: no-cache
Host: tfs-pmo-app:8090
Connection: keep-alive
Authorization: NTLM TlRMTVxxxxxxx - Length 72 chars

Second Response:

HTTP/1.1 401 Unauthorized
Content-Type: text/html; charset=us-ascii
WWW-Authenticate: NTLM TlRMxxxxxx== - Length 354 chars
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 11 May 2021 17:33:00 GMT
Content-Length: 341

Third Request:

GET /tfs/xxx/_git/xxx/info/refs?service=git-upload-pack HTTP/1.1
Accept-Encoding: gzip
Pragma: no-cache
User-Agent: JGit/3.2.0.201312181205-r
Accept: application/x-git-upload-pack-advertisement, */*
Cache-Control: no-cache
Host: tfs-pmo-app:8090
Connection: keep-alive
Authorization: NTLM TlRMTVNxxxxx - Length 256 chars

Third Response:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/x-git-upload-pack-advertisement
Server: Microsoft-IIS/8.5
X-TFS-ProcessId: 76ec3355-4bc2-xxxxxxxxxxxxxx
X-FRAME-OPTIONS: SAMEORIGIN
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Access-Control-Allow-Methods: OPTIONS,GET,POST,PATCH,PUT,DELETE
Access-Control-Expose-Headers: ActivityId,X-TFS-Session
Access-Control-Allow-Headers: authorization
Set-Cookie: Tfs-SessionId=xxxxxxxxxxxx; path=/
Set-Cookie: Tfs-SessionActive=2021-05-11T17:33:01; path=/
X-VSS-UserData: 69b58752-xxxxxxxxxxxxx
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
P3P: CP="CAO xxxxxxxxxxxxxxxxxxxxxxxxx"
X-Content-Type-Options: nosniff
Date: Tue, 11 May 2021 17:33:00 GMT
Content-Length: 1098

What we have tried so far, increasing connection timeout to 300, changing http client in Eclipse Preferences for Git, adding username/password when cloning repo - this doesn't have any visible impact, changing different variations of eclipse with jdk, changing git credentials helper to wincred, manager, store even resetting without any credentials helper, tried configuring cntlm but during test it says that you don't need proxying, none of this seems to work.

This probably means there is a bug in egit/jgit implementation. Looking at the current implementation source and tracing stack from error:

!ENTRY org.eclipse.egit.core 4 0 2021-05-08 04:56:02.018
!MESSAGE Pulling 1 repository
!SUBENTRY 1 org.eclipse.egit.core 4 0 2021-05-08 04:56:02.021
!MESSAGE http://xxxxx:8090/tfs/xxxx/_git/xxx: authentication not supported
!STACK 0
org.eclipse.jgit.api.errors.TransportException: http://xxxxx:8090/tfs/xxxx/_git/xxx: authentication not supported
    at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:224)
    at org.eclipse.jgit.api.PullCommand.call(PullCommand.java:263)
    at org.eclipse.egit.core.op.PullOperation$PullJob.run(PullOperation.java:255)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Caused by: org.eclipse.jgit.errors.TransportException: http://xxxxx:8090/tfs/xxxx/_git/xxx: authentication not supported
    at org.eclipse.jgit.transport.TransportHttp.connect(TransportHttp.java:674)
    at org.eclipse.jgit.transport.TransportHttp.openFetch(TransportHttp.java:465)
    at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:142)
    at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:94)
    at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1309)
    at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:213)
    ... 3 more

https://git.eclipse.org/r/plugins/gitiles/jgit/jgit/+/refs/tags/v5.11.0.202103091610-r/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java

org.eclipse.jgit.transport.TransportHttp.connect(TransportHttp.java:674):

Line 671:   case HttpConnection.HTTP_UNAUTHORIZED:
Line 672:                       authMethod = HttpAuthMethod.scanResponse(conn, ignoreTypes);
Line 673:                       if (authMethod.getType() == HttpAuthMethod.Type.NONE)
Line 674:                           throw new TransportException(uri, MessageFormat.format(
Line 675:                                   JGitText.get().authenticationNotSupported, uri));

Looks like scanResponse method is returning none for auth method type which is causing the issue, so lets review HttpAuthMethod:

https://git.eclipse.org/r/plugins/gitiles/jgit/jgit/+/refs/tags/v5.11.0.202103091610-r/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java

The code here basically checks for 3 authentication methods, BASIC, DIGEST and NEGOTIATE, in our case the header "WWW-Authenticate: NTLM" is none of the supported onces hence the exception.

But the confusing part is how the hell is kepler successfully authenticating for NTLM, the answer probably (through web-searches) is that actually jdk maybe responsible for that as its under HttpURLConnection class is inherently sending NTLM tokens which may not be the case for newer jdks (don't know why).

Conclusion: I don't seem to find the right answers on where does the problem lie?

  1. Is it because of new jdks not inherently supporting NTML (under the hood)?
  2. Shouldn't egit/jgit fall back to other mechanism like BASIC authentication?
  3. Why can't I send my credentials pre-emptively using egit/jgit to bypass NTLM?

P.S. When writing this post, it looks like our server may not have been configured for BASIC authentication support, but I tried different authentication types using git command and they did work. I will check again with wireshark capture and see the underlying mechanism.

Thanks, if you read the whole post :).


Solution

  • I finally managed to resolve the issue.

    Since the kepler version (jdk 1.7) was able to communicate with tfs, so I looked to see if there is something changed in jdks after 1.7 and luckily there was:

    NTLM authentication in HttpURLConnection not working in JRE but works in JDK environment

    How to provide ntlm authentication while calling any url?

    From jdk1.8.0_181 onwards http based ntlm transparent authentication is disabled by default so, just setting it to allHosts fixed the issue.

    All you need to do is comment this line in jre/lib/net.properties file for Java 8, or <JAVA_HOME>/conf/net.properties for Java 11/15:

    #jdk.http.ntlm.transparentAuth=disabled
    

    and uncomment this one:

    jdk.http.ntlm.transparentAuth=allHosts
    

    Also you can set the same using "-Djdk.http.ntlm.transparentAuth=allHosts" as jvm arguments.

    Also since this works with HttpUrlConnection jdk native client so we also need to change git http client configuration to use "Java built-in HTTP" rather than "Apache HTTP".