Skip to content

Commit

Permalink
Fix #10366: Improve messaging when GitHub tokens need SSO authorizati…
Browse files Browse the repository at this point in the history
…on (#10432)
  • Loading branch information
danepowell committed Jan 8, 2022
1 parent 24b62a1 commit 93d4c8e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/Composer/Util/AuthHelper.php
Expand Up @@ -92,6 +92,23 @@ public function promptAuthIfNeeded($url, $origin, $statusCode, $reason = null, $
$message = "\n";

$rateLimited = $gitHubUtil->isRateLimited($headers);
$requiresSso = $gitHubUtil->requiresSso($headers);

if ($requiresSso) {
$ssoUrl = $gitHubUtil->getSsoUrl($headers);
$message = sprintf(
'GitHub API token requires SSO authorization. Authorize this token at ' . $ssoUrl,
$ssoUrl
) . "\n";
$this->io->writeError($message);
if (!$this->io->isInteractive()) {
throw new TransportException('Could not authenticate against ' . $origin, 403);
}
$this->io->ask('After authorizing your token, confirm that you would like to retry the request');

return array('retry' => true, 'storeAuth' => $storeAuth);
}

if ($rateLimited) {
$rateLimit = $gitHubUtil->getRateLimit($headers);
if ($this->io->hasAuthentication($origin)) {
Expand Down
42 changes: 42 additions & 0 deletions src/Composer/Util/GitHub.php
Expand Up @@ -171,6 +171,28 @@ public function getRateLimit(array $headers)
return $rateLimit;
}

/**
* Extract SSO URL from response.
*
* @param string[] $headers Headers from Composer\Downloader\TransportException.
*
* @return string|null
*/
public function getSsoUrl(array $headers)
{
foreach ($headers as $header) {
$header = trim($header);
if (false === stripos($header, 'x-github-sso: required')) {
continue;
}
if (Preg::isMatch('{\burl=(?P<url>[^\s;]+)}', $header, $match)) {
return $match['url'];
}
}

return null;
}

/**
* Finds whether a request failed due to rate limiting
*
Expand All @@ -188,4 +210,24 @@ public function isRateLimited(array $headers)

return false;
}

/**
* Finds whether a request failed due to lacking SSO authorization
*
* @see https://docs.github.com/en/rest/overview/other-authentication-methods#authenticating-for-saml-sso
*
* @param string[] $headers Headers from Composer\Downloader\TransportException.
*
* @return bool
*/
public function requiresSso(array $headers)
{
foreach ($headers as $header) {
if (Preg::isMatch('{^X-GitHub-SSO: required}i', trim($header))) {
return true;
}
}

return false;
}
}

0 comments on commit 93d4c8e

Please sign in to comment.