1
0
Fork 0

Merge pull request #5717 from berlinger-rarents/fix/5584_anon_redirect_bitbucket

prevent (prompt for) bitbucket auth when it redirected
pull/5779/head
Jordi Boggiano 2016-10-10 14:11:24 +02:00 committed by GitHub
commit 183398fe5e
2 changed files with 104 additions and 1 deletions

View File

@ -246,7 +246,10 @@ class RemoteFilesystem
}
if (isset($options['bitbucket-token'])) {
$fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token='.$options['bitbucket-token'];
// skip using the token for BitBucket downloads as these are not working with auth
if (!$this->isPublicBitBucketDownload($origFileUrl)) {
$fileUrl .= (false === strpos($fileUrl,'?') ? '?' : '&') . 'access_token=' . $options['bitbucket-token'];
}
unset($options['bitbucket-token']);
}
@ -342,6 +345,7 @@ class RemoteFilesystem
// check for bitbucket login page asking to authenticate
if ($originUrl === 'bitbucket.org'
&& !$this->isPublicBitBucketDownload($fileUrl)
&& substr($fileUrl, -4) === '.zip'
&& preg_match('{^text/html\b}i', $contentType)
) {
@ -982,4 +986,25 @@ class RemoteFilesystem
return parse_url($url, PHP_URL_HOST).':'.$port;
}
/**
* @link https://github.com/composer/composer/issues/5584
*
* @param string $urlToBitBucketFile URL to a file at bitbucket.org.
*
* @return bool Whether the given URL is a public BitBucket download which requires no authentication.
*/
private function isPublicBitBucketDownload($urlToBitBucketFile)
{
$path = parse_url($urlToBitBucketFile, PHP_URL_PATH);
// Path for a public download follows this pattern /{user}/{repo}/downloads/{whatever}
// {@link https://blog.bitbucket.org/2009/04/12/new-feature-downloads/}
$pathParts = explode('/', $path);
if (count($pathParts) >= 4 && $pathParts[2] != 'downloads') {
return true;
}
return false;
}
}

View File

@ -191,6 +191,84 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
}
}
/**
* Provides URLs to public downloads at BitBucket.
*
* @return string[][]
*/
public function provideBitbucketPublicDownloadUrls()
{
return array(
array('https://bitbucket.org/seldaek/composer-live-test-repo/downloads/composer-unit-test-download-me.txt', '1234'),
);
}
/**
* Tests that a BitBucket public download is correctly retrieved.
*
* @param string $url
* @param string $contents
* @dataProvider provideBitbucketPublicDownloadUrls
*/
public function testBitBucketPublicDownload($url, $contents)
{
$io = $this
->getMockBuilder('Composer\IO\ConsoleIO')
->disableOriginalConstructor()
->getMock();
$rfs = new RemoteFilesystem($io);
$hostname = parse_url($url, PHP_URL_HOST);
$result = $rfs->getContents($hostname, $url, false);
$this->assertEquals($contents, $result);
}
/**
* Tests that a BitBucket public download is correctly retrieved when `bitbucket-oauth` is configured.
*
* @param string $url
* @param string $contents
* @dataProvider provideBitbucketPublicDownloadUrls
*/
public function testBitBucketPublicDownloadWithAuthConfigured($url, $contents)
{
$io = $this
->getMockBuilder('Composer\IO\ConsoleIO')
->disableOriginalConstructor()
->getMock();
$config = $this
->getMockBuilder('Composer\Config')
->getMock();
$config
->method('get')
->withAnyParameters()
->willReturn(array());
$io
->method('hasAuthentication')
->with('bitbucket.org')
->willReturn(true);
$io
->method('getAuthentication')
->with('bitbucket.org')
->willReturn(array(
'username' => 'x-token-auth',
// This token is fake, but it matches a valid token's pattern.
'password' => '1A0yeK5Po3ZEeiiRiMWLivS0jirLdoGuaSGq9NvESFx1Fsdn493wUDXC8rz_1iKVRTl1GINHEUCsDxGh5lZ='
));
$rfs = new RemoteFilesystem($io, $config);
$hostname = parse_url($url, PHP_URL_HOST);
$result = $rfs->getContents($hostname, $url, false);
$this->assertEquals($contents, $result);
}
protected function callGetOptionsForUrl($io, array $args = array(), array $options = array(), $fileUrl = '')
{
$fs = new RemoteFilesystem($io, null, $options);