libgit2 / libgit2sharp

Git + .NET = ❤
http://libgit2.github.com
MIT License
3.12k stars 879 forks source link

'Too many redirects or authentication replays' on clone from TFS #1596

Open MustafaJamal opened 6 years ago

MustafaJamal commented 6 years ago

After updating to Team Foundation Server TFS 2018 & 2017 Update 3, we are not be able to login to GIT repository using LibGit2Sharp library using Access Token. Please check the code below:

    `
    string accessToken = "eyJ0eXAiOiJKV1QiLCJ...";
    NetworkCredential gitCredentials = new NetworkCredential(string.Empty, accessToken);
    string localRepoPath = string.Empty;
    string gitTfsRepo = "http://mjtfs2017:8080/tfs/DefaultCollection/_git/GITTest001";

    try
    {
        localRepoPath = Repository.Clone(gitTfsRepo, @"D:\temp\GIT",
            new CloneOptions()
            {
                CredentialsProvider = GetCredentialsHandler(gitCredentials),
                IsBare = false
            });

    }
    catch (Exception err)
    {
        Console.WriteLine(err);
    }

    Console.WriteLine(localRepoPath);
    `

I communicated with Microsoft TFS/VSTS Team they gave following response:

The fact that you received those responses from the code snip I provided means that your extension is correctly configured (regarding scopes at least) and TFS is correctly accepting the extension’s access token to perform git operations through HTTP, when the git client sends it.

Additionally, if I use the next command, using git for Windows, I’m able to fully interact with a TFS repo with that access token:

git -c http.extraheader="Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ..." clone http://at1-tfs-test1-angallo.westus2.cloudapp.azure.com:8080/tfs/DefaultCollection/_git/test_project_1

But that same command doesn’t work for git for Linux, probably because my git client on my Linux machine doesn’t send or correctly consider these HTTP headers (just as LibGit2Sharp seems to not do too (from your latest Fiddler trace I still see the Authentication header missing)). So I still believe the problem here comes from the git client, not TFS or the access token.

Please suggest, thanks in advance.

LibGit2Sharp version: 0.26.0-preview-0027

ethomson commented 6 years ago

After updating to Team Foundation Server TFS 2018 & 2017 Update 3, we are not be able to login to GIT repository using LibGit2Sharp library using Access Token

Did this work before?

Have you tried creating a Personal Access Token instead of a bearer auth token?

ethomson commented 6 years ago

(Please also be sure to delete that access token, now that it’s been posted publicly.)

MustafaJamal commented 6 years ago

Did this work before?

No it never worked

Have you tried creating a Personal Access Token instead of a bearer auth token?

Yes I tried PAT on TFS 2018 and same exception is occurring.

ethomson commented 6 years ago

I use PATs on TFS 2018 and VSTS with no problem. Can you show me some code or a fiddler or wireshark trace?

MustafaJamal commented 6 years ago

Here is the code:

    `static void Main(string[] args)
    {
        NetworkCredential networkCredential = new NetworkCredential(string.Empty,
            "ssormigjrmdsm7...");
        string localRepoPath = Repository.Clone("http://mr4tfs:8080/tfs/DefaultCollection/_git/GIT001", @"D:\temp\GIT",
            new CloneOptions()
            {
                CredentialsProvider = GetCredentialsHandler(networkCredential),
                IsBare = false
            });
    }

    internal static CredentialsHandler GetCredentialsHandler(NetworkCredential gitCredentials)
    {
        CredentialsHandler credHandler = (url, fromUrl, types) =>
        {
            if ((types & SupportedCredentialTypes.UsernamePassword) == SupportedCredentialTypes.UsernamePassword)
            {
                UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials();
                if (string.IsNullOrEmpty(gitCredentials.Domain) && string.IsNullOrEmpty(gitCredentials.UserName))
                {
                    usernamePasswordCredentials.Username = gitCredentials.Password;
                }
                else
                {
                    if (string.IsNullOrEmpty(gitCredentials.Domain))
                    {
                        usernamePasswordCredentials.Username = gitCredentials.UserName;
                    }
                    else
                    {
                        usernamePasswordCredentials.Username = string.Format("{0}\\{1}", gitCredentials.Domain,
                            gitCredentials.UserName);
                    }
                }

                usernamePasswordCredentials.Password = gitCredentials.Password;

                return usernamePasswordCredentials;
            }

            return new DefaultCredentials();
        };

        return credHandler;
    }`

Fiddler trace:

TFS2018_GIT_AUTH_ERR.zip

MustafaJamal commented 6 years ago

@ethomson waiting for your response.

satyaprakashv commented 5 years ago

Hi @ethomson

Using the blow code i am able to download the complete Repo (GitLab)

_gitrepo = https://repo.mycompany.com/GPP/baseproject.git

But i need to download/clone only selected folder from master branch, is that possible? (I am getting same error - Too many redirects or authentication replays) _gitrepo = https://repo.mycompany.com/GPP/baseproject/tree/master/src/myLibCode

Code Snippet: private static void DownloadGitRepo(string _gitrepo, string _pathtodownload) { var secrets = new SecretStore("git"); var auth = new BasicAuthentication(secrets); var creds = auth.GetCredentials(new TargetUri("https://repo.mycompany.com"));

        var options = new CloneOptions
        {
            CredentialsProvider = (_url, _user, _cred) => new UsernamePasswordCredentials
            {
                Username = creds.Username,
                Password = creds.Password
            },
        };

        Repository.Clone(_gitrepo, _pathtodownload, options);
    }
MustafaJamal commented 5 years ago

@satyaprakashv check the answer of your question here: https://stackoverflow.com/questions/46806069/clone-selected-folders-from-repo

satyaprakashv commented 5 years ago

@MustafaJamal , Thanks, It is very helpful..

rachkoud commented 5 years ago

@MustafaJamal I was digging with this issue all the morning and this is a simple workaround if found with TFS 2018 Update 2 :

LibGit2Sharp.Repository.Clone($"https://usercouldbeanything:{personalaccesstoken}@yourtfsserver/tfs/CollectionName/ProjectName/_git/GitRepoName", "GitRepoName");

If I use the basic auth UsernamePasswordCredentials with the same parameters :

LibGit2Sharp.Repository.Clone("https://yourtfsserver/tfs/CollectionName/ProjectName/_git/GitRepoName", "GitRepoName", new CloneOptions()
{
  CredentialsProvider = (_url, _user, _cred) =>
  {
    return new UsernamePasswordCredentials { Username = "usercouldbeanything", Password = personalaccesstoken };
  }
 });

I'm getting this exception :

LibGit2Sharp.LibGit2SharpException: 'too many redirects or authentication replays'

@ethomson can it be a bug with the librairy?

MustafaJamal commented 5 years ago

@ethomson waiting for your reply. Any update on this ?

BenjaminEhlert commented 5 years ago

Had the same issue here. Turned out that if a wrong password was send once, the user account got locked. Normally in out IT we can enter the password three times, wrongly. I dont think the credentials are send multiple times during Clone? Info: No TFS server, got here via the Issue https://github.com/libgit2/libgit2sharp/issues/1168, which was closed in favor of this issue.

MustafaJamal commented 5 years ago

@ethomson we are waiting for response

Cyberboss commented 3 years ago

I'm getting this on push using the github_actions bot token, which acts a bit weirdly because it's an integration. Any suggestions for that? I've tried a combination of

Using a regular PAT with a real username works as credentials, just fails for the github_actions token it seems.

CrispyDrone commented 3 years ago

NuKeeper switched from version 0.26.2 to 0.27.0-preview-0034 and now I'm getting this error when trying to clone a repository from an Azure Devops Server 2019 instance.

Reverting to 0.26.2 fixes the isssue.

See https://github.com/NuKeeperDotNet/NuKeeper/issues/1042

I will try to investigate the network traffic using wireshark next week.

klapantius commented 3 years ago

@rachkoud thank you for the this hint:

LibGit2Sharp.Repository.Clone($"https://usercouldbeanything:{personalaccesstoken}@yourtfsserver/tfs/CollectionName/ProjectName/_git/GitRepoName", "GitRepoName");

the code runs through without any exception but unfortunately if I then go to the local folder, I find it contains the items from the origin, but a git pull, git fetch or git push results authentication error. Interestingly the error message points to the proper address like [_https://yourtfsserver/tfs/CollectionName/ProjectName/_git/GitRepoName_](). The remote.origin.url entry displayed by git config --list however displays the one in the code snippet above. Pushing changes programmatically using LibGit2Sharp works.

curea commented 3 years ago

NuKeeper switched from version 0.26.2 to 0.27.0-preview-0034 and now I'm getting this error when trying to clone a repository from an Azure Devops Server 2019 instance.

Reverting to 0.26.2 fixes the isssue.

See NuKeeperDotNet/NuKeeper#1042

I will try to investigate the network traffic using wireshark next week.

I found the same issue. Reverting to 0.26.2 allowed me to checkout also.

sfwester commented 2 years ago

Ran into similar issues when trying to clone from an on premise Azure Devops Server 2020 into a docker container.

We were able to get it working by doing the following while having Basic Authentication disabled.

var token = "myPatToken";
var byteArray = Encoding.ASCII.GetBytes(":" + myPatToken);
var encodedToken = Convert.ToBase64String(byteArray);

var options = new CloneOptions
{
    FetchOptions = new FetchOptions
    {
        CustomHeaders = new[]
        {
            $"Authorization: Basic {encodedToken}"
        }
    }
};

return Repository.Clone("https://...", ".", options);
PatrickGrub commented 2 years ago

We use UsernamePasswordCredentials and get the same error message recently. The same code, the cloning with UsernamePasswordCredentials worked before for months and now not anymore.

Any hints? Did change something in the API?

Sherry112 commented 2 years ago

We use UsernamePasswordCredentials and get the same error message recently. The same code, the cloning with UsernamePasswordCredentials worked before for months and now not anymore.

Any hints? Did change something in the API?

Facing the same issue.

mayrbenjamin92 commented 2 years ago

At cognigy we are also facing this issue. It has been working for the last months without issues and started to break for us at the 12. of January. Any ideas of what we can change in order to fix this?

mayrbenjamin92 commented 2 years ago

Hi guys! This response might be surprising, but: We could actually fix this! In my case, our PAT (=Personal access token) was expired! I just had to create a new token and cloning worked, again! Wanted to share this as I was also searching for solutions for quite some time! The error message is just a bit misleading...

@Sherry112, @PatrickGrub :)

manojbaishya commented 2 years ago

Ran into similar issues when trying to clone from an on premise Azure Devops Server 2020 into a docker container.

We were able to get it working by doing the following while having Basic Authentication disabled.

var token = "myPatToken";
var byteArray = Encoding.ASCII.GetBytes(":" + myPatToken);
var encodedToken = Convert.ToBase64String(byteArray);

var options = new CloneOptions
{
    FetchOptions = new FetchOptions
    {
        CustomHeaders = new[]
        {
            $"Authorization: Basic {encodedToken}"
        }
    }
};

return Repository.Clone("https://...", ".", options);

Do you think, we could use a similar approach with Repository.Network.Push() ? (ie with Custom Headers)

zsd4yr commented 1 year ago

If it's helpful, I am able to Clone, Pull, Push, everything in an AzureDevOps git repository with a personal access token (PAT) with Code (Read, Write, and Manage) permissions -- just supply the PAT as password for the username, empty string password in a UsernamePasswordCredentials object, and give that in the Credential Handler

# credential provider:
public static CredentialsHandler GetDefaultCredentialsHandler(string projectName)
     => (_url, _user, _cred) => new UsernamePasswordCredentials
    {
        Username = personalAccessToken;
        Password = string.Empty
    };

# clone method:
var cloneOptions = new CloneOptions
{
    CredentialsProvider = GetDefaultCredentialsHandler(this.ProjectName),
};

Repository.Clone(sourceURL, localClonePath, cloneOptions);
SeppPenner commented 8 months ago

Did anyone get this to work with Github and personal access tokens? Because I don't seem to get this done...

Cyberboss commented 8 months ago

Here's the credentials handler I use today. Seems to work fine: https://github.com/tgstation/tgstation-server/blob/ac290fc6ffce19c41233bb3a8321e984d9c1e722/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs#L83-L108

User/pass is user/token

SeppPenner commented 8 months ago

Here's the credentials handler I use today. Seems to work fine: https://github.com/tgstation/tgstation-server/blob/ac290fc6ffce19c41233bb3a8321e984d9c1e722/src/Tgstation.Server.Host/Components/Repository/LibGit2RepositoryFactory.cs#L83-L108

User/pass is user/token

Mhm, strange. I did it the same way. Maybe the token is corrupt...

andreiZi commented 1 week ago

Ran into similar issues when trying to clone from an on premise Azure Devops Server 2020 into a docker container.

We were able to get it working by doing the following while having Basic Authentication disabled.

var token = "myPatToken";
var byteArray = Encoding.ASCII.GetBytes(":" + myPatToken);
var encodedToken = Convert.ToBase64String(byteArray);

var options = new CloneOptions
{
    FetchOptions = new FetchOptions
    {
        CustomHeaders = new[]
        {
            $"Authorization: Basic {encodedToken}"
        }
    }
};

return Repository.Clone("https://...", ".", options);

I appreciate your approach, as it has successfully resolved the debugging process, which has been ongoing for days and weeks. Specifically, this approach has proven to be the most effective within my TFS DevOps environment.