From 06ee8a2905b6e19234271bf0152991ad2aad8e14 Mon Sep 17 00:00:00 2001 From: kenrowland Date: Fri, 11 Jan 2019 09:29:38 -0500 Subject: [PATCH 1/4] Add support for reauthorization after a timeout period Signed-off-by: kenrowland --- README.md | 6 +++++- composer.json | 3 ++- src/Client.php | 49 ++++++++++++++++++++++++++++++++++++++------ tests/ClientTest.php | 33 +++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 480319b..3700f6f 100755 --- a/README.md +++ b/README.md @@ -24,8 +24,12 @@ $ composer require gliterd/backblaze-b2 use BackblazeB2\Client; use BackblazeB2\Bucket; -$client = new Client('accountId', 'applicationKey'); +$options = ['auth_timeout_seconds' => seconds]; + +$client = new Client('accountId', 'applicationKey', $options); ``` +_$options_ is optional. If omitted, the default timeout is 12 hours. The timeout allows for a long lived Client object +so that the authorization token does not expire. ## *ApplicationKey is not supported yet, please use MasterKey only* #### Returns a bucket details diff --git a/composer.json b/composer.json index ecb1946..7ab51a0 100755 --- a/composer.json +++ b/composer.json @@ -15,7 +15,8 @@ ], "require": { "php": ">=5.5.0", - "guzzlehttp/guzzle": "^6.1" + "guzzlehttp/guzzle": "^6.1", + "nesbot/carbon": "^2.10" }, "require-dev": { "phpunit/phpunit": "4.8.*", diff --git a/src/Client.php b/src/Client.php index a8ffb48..31d36c3 100755 --- a/src/Client.php +++ b/src/Client.php @@ -5,6 +5,7 @@ use BackblazeB2\Exceptions\NotFoundException; use BackblazeB2\Exceptions\ValidationException; use BackblazeB2\Http\Client as HttpClient; +use Carbon\Carbon; class Client { @@ -17,6 +18,9 @@ class Client protected $client; + protected $reauthTime; + protected $authTimeoutSeconds; + /** * Client constructor. Accepts the account ID, application key and an optional array of options. * @@ -29,6 +33,15 @@ public function __construct($accountId, $applicationKey, array $options = []) $this->accountId = $accountId; $this->applicationKey = $applicationKey; + if (isset($options['auth_timeout_seconds'])) { + $this->authTimeoutSeconds = $options['auth_timeout_seconds']; + } else { + $this->authTimeoutSeconds = 12 * 60 * 60; // 12 hour default + } + + // set reauthorize time to force an authentication to take place + $this->reauthTime = Carbon::now('UTC')->subSeconds($this->authTimeoutSeconds * 2); + if (isset($options['client'])) { $this->client = $options['client']; } else { @@ -55,6 +68,8 @@ public function createBucket(array $options) ); } + $this->authorizeAccount(); + $response = $this->client->request('POST', $this->apiUrl.'/b2_create_bucket', [ 'headers' => [ 'Authorization' => $this->authToken, @@ -90,6 +105,8 @@ public function updateBucket(array $options) $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']); } + $this->authorizeAccount(); + $response = $this->client->request('POST', $this->apiUrl.'/b2_update_bucket', [ 'headers' => [ 'Authorization' => $this->authToken, @@ -113,6 +130,8 @@ public function listBuckets() { $buckets = []; + $this->authorizeAccount(); + $response = $this->client->request('POST', $this->apiUrl.'/b2_list_buckets', [ 'headers' => [ 'Authorization' => $this->authToken, @@ -142,6 +161,8 @@ public function deleteBucket(array $options) $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']); } + $this->authorizeAccount(); + $this->client->request('POST', $this->apiUrl.'/b2_delete_bucket', [ 'headers' => [ 'Authorization' => $this->authToken, @@ -173,6 +194,8 @@ public function upload(array $options) $options['BucketId'] = $this->getBucketIdFromName($options['BucketName']); } + $this->authorizeAccount(); + // Retrieve the URL that we should be uploading to. $response = $this->client->request('POST', $this->apiUrl.'/b2_get_upload_url', [ 'headers' => [ @@ -261,6 +284,8 @@ public function download(array $options) $requestUrl = sprintf('%s/file/%s/%s', $this->downloadUrl, $options['BucketName'], $options['FileName']); } + $this->authorizeAccount(); + $response = $this->client->request('GET', $requestUrl, $requestOptions, false); return isset($options['SaveAs']) ? true : $response; @@ -291,6 +316,8 @@ public function listFiles(array $options) $maxFileCount = 1; } + $this->authorizeAccount(); + // B2 returns, at most, 1000 files per "page". Loop through the pages and compile an array of File objects. while (true) { $response = $this->client->request('POST', $this->apiUrl.'/b2_list_file_names', [ @@ -355,6 +382,8 @@ public function getFile(array $options) } } + $this->authorizeAccount(); + $response = $this->client->request('POST', $this->apiUrl.'/b2_get_file_info', [ 'headers' => [ 'Authorization' => $this->authToken, @@ -398,6 +427,8 @@ public function deleteFile(array $options) $options['FileId'] = $file->getId(); } + $this->authorizeAccount(); + $this->client->request('POST', $this->apiUrl.'/b2_delete_file_version', [ 'headers' => [ 'Authorization' => $this->authToken, @@ -418,13 +449,17 @@ public function deleteFile(array $options) */ protected function authorizeAccount() { - $response = $this->client->request('GET', 'https://api.backblazeb2.com/b2api/v1/b2_authorize_account', [ - 'auth' => [$this->accountId, $this->applicationKey], - ]); + if (Carbon::now('UTC')->timestamp > $this->reauthTime->timestamp) { + $response = $this->client->request('GET', 'https://api.backblazeb2.com/b2api/v1/b2_authorize_account', [ + 'auth' => [$this->accountId, $this->applicationKey], + ]); - $this->authToken = $response['authorizationToken']; - $this->apiUrl = $response['apiUrl'].'/b2api/v1'; - $this->downloadUrl = $response['downloadUrl']; + $this->authToken = $response['authorizationToken']; + $this->apiUrl = $response['apiUrl'].'/b2api/v1'; + $this->downloadUrl = $response['downloadUrl']; + $this->reauthTime = Carbon::now('UTC'); + $this->reauthTime->addSeconds($this->authTimeoutSeconds); + } } /** @@ -503,6 +538,8 @@ public function uploadLargeFile(array $options) $options['FileContentType'] = 'b2/x-auto'; } + $this->authorizeAccount(); + // 1) b2_start_large_file, (returns fileId) $start = $this->startLargeFile($options['FileName'], $options['FileContentType'], $options['BucketId']); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index e0499cb..12ab830 100755 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -13,6 +13,8 @@ use BackblazeB2\File; use GuzzleHttp\Middleware; use GuzzleHttp\Psr7\Stream; +use Carbon\Carbon; +use ReflectionClass; class ClientTest extends \PHPUnit_Framework_TestCase { @@ -526,4 +528,35 @@ public function testDeletingNonExistentFileThrowsException() 'FileName' => 'fileName', ])); } + + public function testAuthenticationTimeout() + { + $reflectionClass = new ReflectionClass('BackblazeB2\Client'); + $reflectionProperty = $reflectionClass->getProperty('reauthTime'); + $reflectionProperty->setAccessible(true); + + $guzzle = $this->buildGuzzleFromResponses([ + $this->buildResponseFromStub(200, [], 'authorize_account.json'), + $this->buildResponseFromStub(200, [], 'authorize_account.json'), + $this->buildResponseFromStub(200, [], 'create_bucket_public.json'), + ]); + + $client = new Client('testId', 'testKey', + [ + 'client' => $guzzle, + 'auth_timeout_seconds' => 3, + ]); + + $curTime = $reflectionProperty->getValue($client); + sleep(10); // let the token timeout + + // Something that will reaturhorize + $bucket = $client->createBucket([ + 'BucketName' => 'Test bucket', + 'BucketType' => Bucket::TYPE_PUBLIC, + ]); + + $newTime = $reflectionProperty->getValue($client); + $this->assertTrue($curTime->timestamp != $newTime->timestamp); + } } From 720745176ff0d9313535847c876571b76d201101 Mon Sep 17 00:00:00 2001 From: Ramesh Mhetre Date: Fri, 11 Jan 2019 22:16:11 +0000 Subject: [PATCH 2/4] Apply fixes from StyleCI --- tests/ClientTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 12ab830..96d23ea 100755 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -13,7 +13,6 @@ use BackblazeB2\File; use GuzzleHttp\Middleware; use GuzzleHttp\Psr7\Stream; -use Carbon\Carbon; use ReflectionClass; class ClientTest extends \PHPUnit_Framework_TestCase From 6f622e8cb35cf6d015c2f8166b70907937f2816e Mon Sep 17 00:00:00 2001 From: Ramesh Mhetre Date: Fri, 11 Jan 2019 23:24:33 +0100 Subject: [PATCH 3/4] Restricted to min php version 7.1.8 Signed-off-by: Ramesh Mhetre --- .travis.yml | 1 - composer.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7ac9872..4d27a8d 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: php php: - - '5.6' - '7.0' - '7.1' - nightly diff --git a/composer.json b/composer.json index 7ab51a0..7104e78 100755 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": ">=5.5.0", + "php": "^7.1.8", "guzzlehttp/guzzle": "^6.1", "nesbot/carbon": "^2.10" }, From be91bdf6cca2c2b3c3b449ea2bc8a44fdfeeb0e8 Mon Sep 17 00:00:00 2001 From: Ramesh Mhetre Date: Fri, 11 Jan 2019 23:30:37 +0100 Subject: [PATCH 4/4] Removed php 7.0 Signed-off-by: Ramesh Mhetre --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4d27a8d..841c04f 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: php php: - - '7.0' - '7.1' - nightly