1
0
Fork 0

Fix authentication issues with private bitbucket repos (#11464)

pull/11478/head
Stefan Grootscholten 2023-05-23 23:06:48 +02:00 committed by Jordi Boggiano
parent 9885d23e2a
commit 9d965b9c65
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
2 changed files with 73 additions and 0 deletions

View File

@ -28,6 +28,8 @@ class AuthHelper
protected $config; protected $config;
/** @var array<string, string> Map of origins to message displayed */ /** @var array<string, string> Map of origins to message displayed */
private $displayedOriginAuthentications = []; private $displayedOriginAuthentications = [];
/** @var array<string, bool> Map of URLs and whether they already retried with authentication from Bitbucket */
private $bitbucketRetry = [];
public function __construct(IOInterface $io, Config $config) public function __construct(IOInterface $io, Config $config)
{ {
@ -164,6 +166,12 @@ class AuthHelper
$this->io->setAuthentication($origin, 'x-token-auth', $accessToken); $this->io->setAuthentication($origin, 'x-token-auth', $accessToken);
$askForOAuthToken = false; $askForOAuthToken = false;
} }
} elseif (!isset($this->bitbucketRetry[$url])) {
// when multiple requests fire at the same time, they will all fail and the first one resets the token to be correct above but then the others
// reach the code path and without this fallback they would end up throwing below
// see https://github.com/composer/composer/pull/11464 for more details
$askForOAuthToken = false;
$this->bitbucketRetry[$url] = true;
} else { } else {
throw new TransportException('Could not authenticate against ' . $origin, 401); throw new TransportException('Could not authenticate against ' . $origin, 401);
} }

View File

@ -538,6 +538,71 @@ class AuthHelperTest extends TestCase
$this->authHelper->promptAuthIfNeeded('https://gitlab.com/acme/archive.zip', $origin, 404, 'GitLab requires authentication and it was not provided'); $this->authHelper->promptAuthIfNeeded('https://gitlab.com/acme/archive.zip', $origin, 404, 'GitLab requires authentication and it was not provided');
} }
public function testPromptAuthIfNeededMultipleBitbucketDownloads(): void
{
$origin = 'bitbucket.org';
$expectedResult = [
'retry' => true,
'storeAuth' => false,
];
$authConfig = [
'bitbucket.org' => [
'access-token' => 'bitbucket_access_token',
'access-token-expiration' => time() + 1800,
]
];
$this->config
->method('get')
->willReturnMap([
['github-domains', 0, []],
['gitlab-domains', 0, []],
['bitbucket-oauth', 0, $authConfig],
['github-domains', 0, []],
['gitlab-domains', 0, []],
]);
$this->io
->expects($this->exactly(2))
->method('hasAuthentication')
->with($origin)
->willReturn(true);
$getAuthenticationReturnValues = [
['username' => 'bitbucket_client_id', 'password' => 'bitbucket_client_secret'],
['username' => 'x-token-auth', 'password' => 'bitbucket_access_token'],
];
$this->io
->expects($this->exactly(2))
->method('getAuthentication')
->willReturnCallback(
function ($repositoryName) use (&$getAuthenticationReturnValues) {
return array_shift($getAuthenticationReturnValues);
}
);
$this->io
->expects($this->once())
->method('setAuthentication')
->with($origin, 'x-token-auth', 'bitbucket_access_token');
$result1 = $this->authHelper->promptAuthIfNeeded('https://bitbucket.org/workspace/repo1/get/hash1.zip', $origin, 401, 'HTTP/2 401 ');
$result2 = $this->authHelper->promptAuthIfNeeded('https://bitbucket.org/workspace/repo2/get/hash2.zip', $origin, 401, 'HTTP/2 401 ');
$this->assertSame(
$expectedResult,
$result1
);
$this->assertSame(
$expectedResult,
$result2
);
}
/** /**
* @param array<string, string|null> $auth * @param array<string, string|null> $auth
* *