I’m using Git to clone a repo hosted on an Azure DevOps server. I have been using it for a while from some clients. (Usually from Visual Studio.) Now I have installed Git on a new client (Visual Studio is not installed on that one) and I am not able to connect. Git version is 2.43.0.windows.1 on all clients and the git configs are also the same.
This is what happens: (Initially the same on the client where it is working and the one where it fails. I have replaced the repo name and the domain name. Logs are not complete.)
17:26:46.553926 http.c:829 => Send header: GET /Global/myrepo/_git/myrepo/info/refs?service=git-upload-pack HTTP/1.1
17:26:46.553926 http.c:829 => Send header: Host: devops.mydomain.com
17:26:46.559921 http.c:829 <= Recv header: HTTP/1.1 401 Unauthorized
17:26:46.560910 http.c:829 <= Recv header: X-TFS-ServiceError: TF400813%3A%20Resource%20not%20available%20for%20anonymous%20access.%20Client%20authentication%20required.
17:26:46.560910 http.c:829 <= Recv header: WWW-Authenticate: Bearer
17:26:46.560910 http.c:829 <= Recv header: WWW-Authenticate: Basic realm=”https://devops.mydomain.com/”
17:26:46.560910 http.c:829 <= Recv header: WWW-Authenticate: Negotiate
17:26:46.568918 http.c:829 <= Recv header: WWW-Authenticate: NTLM
17:26:46.568918 http.c:829 <= Recv header: X-Powered-By: ASP.NET
17:26:46.568918 http.c:829 <= Recv header: P3P: CP=”CAO DSP COR ADMa DEV CONo TELo CUR PSA PSD TAI IVDo OUR SAMi BUS DEM NAV STA UNI COM INT PHY ONL FIN PUR LOC CNT”
17:26:46.568918 http.c:829 <= Recv header: Lfs-Authenticate: NTLM
17:26:46.568918 http.c:829 <= Recv header: X-Content-Type-Options: nosniff
17:26:46.568918 http.c:829 <= Recv header: Date: Thu, 16 May 2024 15:26:45 GMT
17:26:46.568918 http.c:829 <= Recv header: Content-Length: 20098
17:26:46.568918 http.c:870 == Info: Connection #0 to host devops.mydomain.com left intact
17:26:46.568918 run-command.c:659 trace: run_command: ‘git credential-manager get’
So the host basically rejects and says NTLM authentication is required. Git starts credential-manager. That seems expected.
17:26:47.017926 …GitCommandBase.cs:32 trace: [ExecuteAsync] Start ‘get’ command…
17:26:47.030926 …GitCommandBase.cs:47 trace: [ExecuteAsync] protocol=https
17:26:47.030926 …GitCommandBase.cs:47 trace: [ExecuteAsync] host=devops.mydomain.com
17:26:47.031925 …GitCommandBase.cs:47 trace: [ExecuteAsync] wwwauth[]=Bearer
17:26:47.032925 …GitCommandBase.cs:47 trace: [ExecuteAsync] wwwauth[]=Basic realm=”https://devops.mydomain.com/”
17:26:47.032925 …GitCommandBase.cs:47 trace: [ExecuteAsync] wwwauth[]=Negotiate
17:26:47.033926 …GitCommandBase.cs:47 trace: [ExecuteAsync] wwwauth[]=NTLM
17:26:47.037925 …oviderRegistry.cs:99 trace: [GetProviderAsync] Host provider override was set id=’generic’
17:26:47.042927 …HostProvider.cs:126 trace: [GetCredentialAsync] Looking for existing credential in store with service=https://devops.mydomain.com account=…
17:26:47.047924 …HostProvider.cs:131 trace: [GetCredentialAsync] No existing credentials found.
17:26:47.047924 …HostProvider.cs:134 trace: [GetCredentialAsync] Creating new credential…
17:26:47.050928 …ricOAuthConfig.cs:38 trace: [TryGet] Invalid OAuth configuration – missing/invalid authorize endpoint:
17:26:47.051927 …icHostProvider.cs:86 trace: [GenerateCredentialAsync] Checking host ‘https://devops.mydomain.com/’ for Windows Integrated Authentication…
17:26:47.052926 …Authentication.cs:34 trace: [GetIsSupportedAsync] HTTP: HEAD https://devops.mydomain.com/
17:26:47.054928 …pClientFactory.cs:60 trace: [CreateClient] Creating new HTTP client instance…
17:26:47.087910 …pClientFactory.cs:80 trace: [CreateClient] Git’s SSL/TLS backend is: Schannel
17:26:47.127915 trace.c:414 performance: 0.000943100 s: git command: ‘C:/Program Files/Git/mingw64/libexec/git-coregit.exe’ config –null –type=path http.https://devops.mydomain.com.sslCAInfo
17:26:47.259915 trace.c:414 performance: 0.000898500 s: git command: ‘C:/Program Files/Git/mingw64/libexec/git-coregit.exe’ config –null –type=path http.devops.mydomain.com.cookieFile
17:26:47.407928 …Authentication.cs:37 trace: [GetIsSupportedAsync] HTTP: Response code ignored.
17:26:47.408912 …Authentication.cs:39 trace: [GetIsSupportedAsync] Inspecting WWW-Authenticate headers…
17:26:47.408912 …Authentication.cs:44 trace: [GetIsSupportedAsync] Found WWW-Authenticate header for Negotiate
17:26:47.409924 …Authentication.cs:49 trace: [GetIsSupportedAsync] Found WWW-Authenticate header for NTLM
17:26:47.409924 …icHostProvider.cs:95 trace: [GenerateCredentialAsync] Host supports WIA – generating empty credential…
17:26:47.410922 …HostProvider.cs:136 trace: [GetCredentialAsync] Credential created.
17:26:47.410922 …GetCommand.cs:39 trace: [ExecuteInternalAsync] Writing credentials to output:
17:26:47.411926 …GetCommand.cs:40 trace: [ExecuteInternalAsync] protocol=https
17:26:47.412921 …GetCommand.cs:40 trace: [ExecuteInternalAsync] host=devops.mydomain.com
17:26:47.412921 …GetCommand.cs:40 trace: [ExecuteInternalAsync] username=
17:26:47.413910 …GetCommand.cs:40 trace: [ExecuteInternalAsync] password=*******
17:26:47.413910 …GitCommandBase.cs:53 trace: [ExecuteAsync] End ‘get’ command…
Here it seems that credential-manager says “Windows Integrated Authentication is supported so I will generate empty credentials.” I don’t really understand this part. It also says something about “http.https://devops.mydomain.com.sslCAInfo” and “http.devops.mydomain.com.cookieFile”.
On the client where I’m able to authenticate I can then see this:
17:26:47.447929 http.c:870 == Info: Issue another request to this URL: ‘https://devops.mydomain.com/Global/myrepo/_git/myrepo/info/refs?service=git-upload-pack’
17:26:47.447929 http.c:870 == Info: Found bundle for host: 0x1bf7c45eb40 [serially]
17:26:47.447929 http.c:870 == Info: Re-using existing connection with host devops.mydomain.com
17:26:47.450929 http.c:870 == Info: Server auth using NTLM with user ”
17:26:47.450929 http.c:817 => Send header, 0000000986 bytes (0x000003da)
17:26:47.450929 http.c:829 => Send header: GET /Global/myrepo/_git/myrepo/info/refs?service=git-upload-pack HTTP/1.1
17:26:47.478932 http.c:829 <= Recv header: HTTP/1.1 200 OK
But on the client where authentication fails it looks like this:
17:45:36.405272 http.c:870 == Info: Issue another request to this URL: ‘https://devops.mydomain.com/Global/myrepo/_git/myrepo/info/refs?service=git-upload-pack’
17:45:36.405272 http.c:870 == Info: Found bundle for host: 0x2516d4eea40 [serially]
17:45:36.405272 http.c:870 == Info: Re-using existing connection with host devops.mydomain.com
17:45:36.407266 http.c:870 == Info: Server auth using NTLM with user ”
17:45:36.407266 http.c:817 => Send header, 0000000394 bytes (0x0000018a)
17:45:36.407266 http.c:829 => Send header: GET /Global/myrepo/_git/myrepo/info/refs?service=git-upload-pack HTTP/1.1
17:45:36.414255 http.c:829 <= Recv header: HTTP/1.1 401 Unauthorized
17:45:36.414255 http.c:870 == Info: NTLM handshake rejected
17:45:36.414255 http.c:870 == Info: Authentication problem. Ignoring this.
The header is significantly smaller, so I guess some authentication information is missing. My Google skills might not be strong enough, I have not been able to figure out how the NTLM authentication works. Where does Git get the credentials from (obviously not stored by git credential manager), how is it included in the header and what could be the reasons for the failure on one client?