1
0
Fork 0

Always check for OAuth token in git config, fixes #1243

pull/1186/merge
Jordi Boggiano 2012-10-22 17:11:34 +02:00
parent b4bcc5b5c8
commit bebd1ce9c7
5 changed files with 66 additions and 32 deletions

View File

@ -80,7 +80,11 @@ class FileDownloader implements DownloaderInterface
if (404 === $e->getCode() && 'github.com' === parse_url($processUrl, PHP_URL_HOST)) { if (404 === $e->getCode() && 'github.com' === parse_url($processUrl, PHP_URL_HOST)) {
$message = "\n".'Could not fetch '.$processUrl.', enter your GitHub credentials to access private repos'; $message = "\n".'Could not fetch '.$processUrl.', enter your GitHub credentials to access private repos';
$gitHubUtil = new GitHub($this->io, $this->config, null, $this->rfs); $gitHubUtil = new GitHub($this->io, $this->config, null, $this->rfs);
$gitHubUtil->authorizeOAuth('github.com', $message); if (!$gitHubUtil->authorizeOAuth('github.com')
&& (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively('github.com', $message))
) {
throw $e;
}
$this->rfs->copy(parse_url($processUrl, PHP_URL_HOST), $processUrl, $fileName); $this->rfs->copy(parse_url($processUrl, PHP_URL_HOST), $processUrl, $fileName);
} else { } else {
throw $e; throw $e;

View File

@ -285,19 +285,24 @@ class GitDownloader extends VcsDownloader
$command = call_user_func($commandCallable, $url); $command = call_user_func($commandCallable, $url);
if (0 !== $this->process->execute($command, $handler)) { if (0 !== $this->process->execute($command, $handler)) {
// private github repository without git access, try https with auth // private github repository without git access, try https with auth
if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match) && $this->io->isInteractive()) { if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match)) {
if (!$this->io->hasAuthorization($match[1])) { if (!$this->io->hasAuthorization($match[1])) {
$message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
$gitHubUtil = new GitHub($this->io, $this->config, $this->process); $gitHubUtil = new GitHub($this->io, $this->config, $this->process);
$gitHubUtil->authorizeOAuth($match[1], $message); $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
if (!$gitHubUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
$gitHubUtil->authorizeOAuthInteractively($match[1], $message);
}
} }
$auth = $this->io->getAuthorization($match[1]); if ($this->io->hasAuthorization($match[1])) {
$url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@'.$match[1].'/'.$match[2].'.git'; $auth = $this->io->getAuthorization($match[1]);
$url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@'.$match[1].'/'.$match[2].'.git';
$command = call_user_func($commandCallable, $url); $command = call_user_func($commandCallable, $url);
if (0 === $this->process->execute($command, $handler)) { if (0 === $this->process->execute($command, $handler)) {
return; return;
}
} }
} }

View File

@ -244,6 +244,8 @@ class GitHubDriver extends VcsDriver
try { try {
return parent::getContents($url); return parent::getContents($url);
} catch (TransportException $e) { } catch (TransportException $e) {
$gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
switch ($e->getCode()) { switch ($e->getCode()) {
case 401: case 401:
case 404: case 404:
@ -252,17 +254,25 @@ class GitHubDriver extends VcsDriver
throw $e; throw $e;
} }
if (!$this->io->isInteractive()) { if ($gitHubUtil->authorizeOAuth($this->originUrl)) {
return $this->attemptCloneFallback($e); return parent::getContents($url);
} }
$this->authorizeOAuth('Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)'); if (!$this->io->isInteractive()) {
return $this->attemptCloneFallback();
}
$gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
return parent::getContents($url); return parent::getContents($url);
case 403: case 403:
if (!$this->io->hasAuthorization($this->originUrl) && $gitHubUtil->authorizeOAuth($this->originUrl)) {
return parent::getContents($url);
}
if (!$this->io->isInteractive() && $fetchingRepoData) { if (!$this->io->isInteractive() && $fetchingRepoData) {
return $this->attemptCloneFallback($e); return $this->attemptCloneFallback();
} }
$rateLimited = false; $rateLimited = false;
@ -278,7 +288,7 @@ class GitHubDriver extends VcsDriver
throw $e; throw $e;
} }
$this->authorizeOAuth('API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)'); $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)');
return parent::getContents($url); return parent::getContents($url);
} }
@ -346,10 +356,4 @@ class GitHubDriver extends VcsDriver
throw $e; throw $e;
} }
} }
protected function authorizeOAuth($message)
{
$gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
$gitHubUtil->authorizeOAuth($this->originUrl, $message);
}
} }

View File

@ -44,20 +44,36 @@ class GitHub
} }
/** /**
* Authorizes a GitHub domain via OAuth * Attempts to authorize a GitHub domain via OAuth
* *
* @param string $originUrl The host this GitHub instance is located at * @param string $originUrl The host this GitHub instance is located at
* @param string $message The reason this authorization is required * @return bool true on success
*/ */
public function authorizeOAuth($originUrl, $message = null) public function authorizeOAuth($originUrl)
{ {
if ('github.com' !== $originUrl) {
return false;
}
// if available use token from git config // if available use token from git config
if (0 === $this->process->execute('git config github.accesstoken', $output)) { if (0 === $this->process->execute('git config github.accesstoken', $output)) {
$this->io->setAuthorization($originUrl, trim($output), 'x-oauth-basic'); $this->io->setAuthorization($originUrl, trim($output), 'x-oauth-basic');
return; return true;
} }
return false;
}
/**
* Authorizes a GitHub domain interactively via OAuth
*
* @param string $originUrl The host this GitHub instance is located at
* @param string $message The reason this authorization is required
* @return bool true on success
*/
public function authorizeOAuthInteractively($originUrl, $message = null)
{
$attemptCounter = 0; $attemptCounter = 0;
if ($message) { if ($message) {
@ -105,7 +121,7 @@ class GitHub
$githubTokens[$originUrl] = $contents['token']; $githubTokens[$originUrl] = $contents['token'];
$this->config->getConfigSource()->addConfigSetting('github-oauth', $githubTokens); $this->config->getConfigSource()->addConfigSetting('github-oauth', $githubTokens);
return; return true;
} }
throw new \RuntimeException("Invalid GitHub credentials 5 times in a row, aborting."); throw new \RuntimeException("Invalid GitHub credentials 5 times in a row, aborting.");

View File

@ -264,30 +264,35 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
$process->expects($this->at(0)) $process->expects($this->at(0))
->method('execute') ->method('execute')
->with($this->stringContains($repoSshUrl)) ->with($this->equalTo('git config github.accesstoken'))
->will($this->returnValue(0)); ->will($this->returnValue(1));
$process->expects($this->at(1)) $process->expects($this->at(1))
->method('execute') ->method('execute')
->with($this->stringContains('git tag')); ->with($this->stringContains($repoSshUrl))
->will($this->returnValue(0));
$process->expects($this->at(2)) $process->expects($this->at(2))
->method('execute')
->with($this->stringContains('git tag'));
$process->expects($this->at(3))
->method('splitLines') ->method('splitLines')
->will($this->returnValue(array($identifier))); ->will($this->returnValue(array($identifier)));
$process->expects($this->at(3)) $process->expects($this->at(4))
->method('execute') ->method('execute')
->with($this->stringContains('git branch --no-color --no-abbrev -v')); ->with($this->stringContains('git branch --no-color --no-abbrev -v'));
$process->expects($this->at(4)) $process->expects($this->at(5))
->method('splitLines') ->method('splitLines')
->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior'))); ->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior')));
$process->expects($this->at(5)) $process->expects($this->at(6))
->method('execute') ->method('execute')
->with($this->stringContains('git branch --no-color')); ->with($this->stringContains('git branch --no-color'));
$process->expects($this->at(6)) $process->expects($this->at(7))
->method('splitLines') ->method('splitLines')
->will($this->returnValue(array('* test_master'))); ->will($this->returnValue(array('* test_master')));