Fix authentication issues with private bitbucket repos (#11464)
parent
9885d23e2a
commit
9d965b9c65
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue