From 00e5fa8c38a0d5b5082760409efc64aea513e1db Mon Sep 17 00:00:00 2001 From: Jesse Scott Date: Mon, 16 May 2016 12:56:06 -0700 Subject: [PATCH] (RK-243) Refuse to generate rugged credentials more than 50 times. The new behavior as of libgit2/rugged 0.24.0 is to continue to call the credentials callback until either it raises an error or the server gives up. Since neither was happening for HTTP sources, invalid credentials were leading to an infinite retry loop. SSH sources already seemed to have a client side abort at around 50 attempts. --- lib/r10k/git/rugged/credentials.rb | 9 +++++++++ spec/unit/git/rugged/credentials_spec.rb | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/lib/r10k/git/rugged/credentials.rb b/lib/r10k/git/rugged/credentials.rb index 23832b640..58d95f17a 100644 --- a/lib/r10k/git/rugged/credentials.rb +++ b/lib/r10k/git/rugged/credentials.rb @@ -12,9 +12,18 @@ class R10K::Git::Rugged::Credentials # @param repository [R10K::Git::Rugged::BaseRepository] def initialize(repository) @repository = repository + @called = 0 end def call(url, username_from_url, allowed_types) + @called += 1 + + # Break out of infinite HTTP auth retry loop introduced in libgit2/rugged 0.24.0, libssh + # auth seems to already abort after ~50 attempts. + if @called > 50 + raise R10K::Git::GitError.new("Authentication failed for Git remote #{url.inspect}.") + end + if allowed_types.include?(:ssh_key) get_ssh_key_credentials(url, username_from_url) elsif allowed_types.include?(:plaintext) diff --git a/spec/unit/git/rugged/credentials_spec.rb b/spec/unit/git/rugged/credentials_spec.rb index 729275118..d712f1215 100644 --- a/spec/unit/git/rugged/credentials_spec.rb +++ b/spec/unit/git/rugged/credentials_spec.rb @@ -99,5 +99,11 @@ it "creates default credentials when no other types are allowed" do expect(subject.call("https://tessier-ashpool.freeside/repo.git", nil, [])).to be_a_kind_of(Rugged::Credentials::Default) end + + it "refuses to generate credentials more than 50 times" do + (1..50).each { subject.call("https://tessier-ashpool.freeside/repo.git", nil, [:plaintext]) } + + expect { subject.call("https://tessier-ashpool.freeside/repo.git", nil, [:plaintext]) }.to raise_error(R10K::Git::GitError, /authentication failed/i) + end end end