Skip to content

Commit

Permalink
Fix race condition where multiple http requests requiring auth end up…
Browse files Browse the repository at this point in the history
… failing, fixes #10763
  • Loading branch information
Seldaek committed May 11, 2022
1 parent 1d0fa93 commit aeb204b
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 4 deletions.
10 changes: 9 additions & 1 deletion src/Composer/Util/AuthHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ function ($value) {
* @param int $statusCode HTTP status code that triggered this call
* @param string|null $reason a message/description explaining why this was called
* @param string[] $headers
* @param int $retryCount the amount of retries already done on this URL
* @return array|null containing retry (bool) and storeAuth (string|bool) keys, if retry is true the request should be
* retried, if storeAuth is true then on a successful retry the authentication should be persisted to auth.json
* @phpstan-return ?array{retry: bool, storeAuth: string|bool}
*/
public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array())
public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $headers = array(), $retryCount = 0)
{
$storeAuth = false;

Expand Down Expand Up @@ -200,8 +201,15 @@ public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $

throw new TransportException($message, $statusCode);
}

// fail if we already have auth
if ($this->io->hasAuthentication($origin)) {
// if two or more requests are started together for the same host, and the first
// received authentication already, we let the others retry before failing them
if ($retryCount === 0) {
return array('retry' => true, 'storeAuth' => false);
}

throw new TransportException("Invalid credentials for '" . $url . "', aborting.", $statusCode);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Composer/Util/Http/CurlDownloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ private function handleRedirect(array $job, Response $response)
private function isAuthenticatedRetryNeeded(array $job, Response $response)
{
if (in_array($response->getStatusCode(), array(401, 403)) && $job['attributes']['retryAuthFailure']) {
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders());
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], $response->getStatusCode(), $response->getStatusMessage(), $response->getHeaders(), $job['attributes']['retries']);

if ($result['retry']) {
return $result;
Expand Down Expand Up @@ -560,7 +560,7 @@ private function isAuthenticatedRetryNeeded(array $job, Response $response)

if ($needsAuthRetry) {
if ($job['attributes']['retryAuthFailure']) {
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], 401);
$result = $this->authHelper->promptAuthIfNeeded($job['url'], $job['origin'], 401, null, array(), $job['attributes']['retries']);
if ($result['retry']) {
return $result;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Composer/Util/RemoteFilesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ protected function callbackGet($notificationCode, $severity, $message, $messageC
*/
protected function promptAuthAndRetry($httpStatus, $reason = null, $headers = array())
{
$result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers);
$result = $this->authHelper->promptAuthIfNeeded($this->fileUrl, $this->originUrl, $httpStatus, $reason, $headers, 1 /** always pass 1 as RemoteFilesystem is single threaded there is no race condition possible */);

$this->storeAuth = $result['storeAuth'];
$this->retry = $result['retry'];
Expand Down

0 comments on commit aeb204b

Please sign in to comment.