Mugen
Mugen

Reputation: 9095

Using TFS Rest API works from curl but not from client dotnet library

I'm using the following code from the library Microsoft.VisualStudio.Services.Client:

var credential = new VssBasicCredential("", "<PAT>");
var url = "<url>"";
using var vssConnection = new VssConnection(new Uri(url), credential);
await vssConnection.ConnectAsync();

It fails with the following exception, which I assume has to do with server not allowing basic auth:

System.ComponentModel.Win32Exception (0x80090020): GSSAPI operation failed with error - Unspecified GSS failure.  Minor code may provide more information (SPNEGO cannot find mechanisms to negotiate).
   at System.Net.NTAuthentication.GetOutgoingBlob(Byte[] incomingBlob, Boolean throwOnError, SecurityStatusPal& statusCode)
   at System.Net.NTAuthentication.GetOutgoingBlob(String incomingBlob)
   at System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean isProxyAuth, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.AuthenticationHelper.SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, Boolean preAuthenticate, Boolean isProxyAuth, Boolean doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
   at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.Common.VssHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.Common.VssHttpRetryMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.SendAsync(HttpRequestMessage message, HttpCompletionOption completionOption, Object userState, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.SendAsync[T](HttpRequestMessage message, Object userState, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.Location.Client.LocationHttpClient.GetConnectionDataAsync(ConnectOptions connectOptions, Int64 lastChangeId, CancellationToken cancellationToken, Object userState)
   at Microsoft.VisualStudio.Services.WebApi.Location.VssServerDataProvider.GetConnectionDataAsync(ConnectOptions connectOptions, Int32 lastChangeId, CancellationToken cancellationToken)
   at Microsoft.VisualStudio.Services.WebApi.Location.VssServerDataProvider.ConnectAsync(ConnectOptions connectOptions, CancellationToken cancellationToken)

However, I manage to execute REST command successfully from command line

curl <url>/_apis/projects -u :<PAT>

I'm using Azure Devops Server 2019 for which I cannot modify any configurations. I'm running the code from dotnet-core Alpine docker image.

Is it a limitation of the dotnet library or am I using it wrong?

Upvotes: 1

Views: 947

Answers (4)

Frank
Frank

Reputation: 11

I had the same error in a program that ran in a Docker container. The cause was an expired PAT. This was not very clear from the error message ("SPNEGO cannot find mechanisms to negotiate"). In addition, the expired PAT still worked on my development machine. That's why I didn't even think that the PAT could have expired.

Newly generated PAT: Everything is running.

Upvotes: 1

LunicLynx
LunicLynx

Reputation: 1098

I got this error with an expired AccessToken.

Verified this with curl.

After creating a new Token it worked.

Upvotes: 1

Mugen
Mugen

Reputation: 9095

The issue was with the Alpine distribution of dotnet Docker image, it does not yet support gss-ntlmssp. Switching to the standard image (Ubuntu based - mcr.microsoft.com/dotnet/core/aspnet:3.1) solved the issue.

Upvotes: 0

Levi Lu-MSFT
Levi Lu-MSFT

Reputation: 30313

If you want to use GitHttpClient, As @Shayki Abramczyk pointed out you should use vssConnection.GetClient<GitHttpClient>() to get GitHttpClient connection.

var credential = new VssBasicCredential("", "<PAT>");
var url = "<url>"";
using var vssConnection = new VssConnection(new Uri(url), credential);
GitHttpClient gitClient = vssConnection.GetClient<GitHttpClient>();

You can follow the examples in the QuickStarts and Samples from Microsoft documents

Upvotes: 0

Related Questions