From 222db27fc8d9aabf21574e9a33f5afc9463d18ac Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Mon, 30 Mar 2020 15:27:49 +0100 Subject: [PATCH] Token retry (#2) * support clearing tokens, retry * clear tokens on connection and endpoint * correctly delete token file --- src/ApiEndpoint.php | 13 ++++ src/ApiRequest.php | 78 ++++++++++--------- src/Connections/AbstractConnection.php | 6 ++ src/IApiConnection.php | 5 ++ src/IApiEndpoint.php | 2 + src/OAuth/TokenStorage/ITokenStorage.php | 7 ++ .../TokenStorage/MemcachedTokenStorage.php | 5 ++ .../TokenStorage/TempFileTokenStorage.php | 6 ++ 8 files changed, 84 insertions(+), 38 deletions(-) diff --git a/src/ApiEndpoint.php b/src/ApiEndpoint.php index c306fb4..984f47a 100644 --- a/src/ApiEndpoint.php +++ b/src/ApiEndpoint.php @@ -73,6 +73,19 @@ function () { ); } + public function clearToken() + { + $connection = $this->_getConnection(); + if($connection) + { + $connection->clearToken(); + } + if($this->_grant !== null) + { + $this->getTokenStorage()->clearToken($this->_grant->getKey()); + } + } + public function setApiDefinition(IApiDefinition $definition) { $this->_definition = $definition; diff --git a/src/ApiRequest.php b/src/ApiRequest.php index d985780..4438e3f 100644 --- a/src/ApiRequest.php +++ b/src/ApiRequest.php @@ -4,6 +4,7 @@ use Fortifi\Api\Core\Exceptions\ApiException; use Fortifi\Api\Core\Exceptions\Client\ClientApiException; use Fortifi\Api\Core\Exceptions\Client\ForbiddenException; +use Packaged\Helpers\RetryHelper; use Packaged\Helpers\ValueAs; class ApiRequest implements IApiRequest @@ -57,6 +58,32 @@ public function setRawResult(IApiResult $result) return $this; } + /** + * @return IApiResult + * @throws ClientApiException + * @throws ForbiddenException + */ + protected function _getRawResult() + { + if($this->hasConnection()) + { + if($this->_requestDetail->requiresAuth()) + { + $this->_connection->setToken($this->_endpoint->getToken()); + $result = $this->_connection->load($this); + if($result->getRawResult()->getStatusCode() == 403) + { + $msg = $result->getRawResult()->getStatusMessage(); + throw new ForbiddenException($msg == 'OK' ? 'Invalid token' : $msg); + } + return $result->getRawResult(); + } + + return $this->_connection->load($this)->getRawResult(); + } + throw new ClientApiException("No API Connection Available", 428); + } + /** * @inheritdoc */ @@ -64,51 +91,26 @@ public function getRawResult() { if($this->_result === null) { - if($this->hasConnection()) + try { - if($this->_requestDetail->requiresAuth()) - { - $this->_getConnection()->setToken($this->_endpoint->getToken()); - try - { - $this->_result = false; - $result = $this->_getConnection()->load($this); - if($result->getRawResult()->getStatusCode() == 403) - { - $msg = $result->getRawResult()->getStatusMessage(); - $this->_result = new ForbiddenException( - $msg == 'OK' ? 'Invalid token' : $msg - ); - throw $this->_result; - } - } - catch(\Exception $e) - { + $this->_result = RetryHelper::retry( + 1, + function () { + return $this->_getRawResult(); + }, + function (\Exception $e) { if($e->getCode() == 403 && stristr($e->getMessage(), 'token')) { - $result = $this->_getConnection()->load($this); - } - else - { - $this->_result = ApiException::build( - $e->getCode(), - $e->getMessage(), - $e - ); - throw $this->_result; + $this->_connection->clearToken(); + $this->_endpoint->clearToken(); } + return true; } - } - else - { - $result = $this->_getConnection()->load($this); - } - - $this->setRawResult($result->getRawResult()); + ); } - else + catch(\Exception $e) { - throw new ClientApiException("No API Connection Available", 428); + $this->_result = ApiException::build($e->getCode(), $e->getMessage(), $e); } } diff --git a/src/Connections/AbstractConnection.php b/src/Connections/AbstractConnection.php index 00915ba..5af684b 100644 --- a/src/Connections/AbstractConnection.php +++ b/src/Connections/AbstractConnection.php @@ -36,6 +36,12 @@ public function setToken(IToken $token) return $this; } + public function clearToken() + { + $this->_token = null; + return $this; + } + protected function _buildHeaders(IApiRequestDetail $request) { $headers = $request->getHeaders(); diff --git a/src/IApiConnection.php b/src/IApiConnection.php index 3ebfb1b..3ce3341 100644 --- a/src/IApiConnection.php +++ b/src/IApiConnection.php @@ -32,4 +32,9 @@ public function setOrganisationFid($fid); * @return $this */ public function setToken(IToken $token); + + /** + * @return $this + */ + public function clearToken(); } diff --git a/src/IApiEndpoint.php b/src/IApiEndpoint.php index 06f83c1..fcea4b2 100644 --- a/src/IApiEndpoint.php +++ b/src/IApiEndpoint.php @@ -16,4 +16,6 @@ public function setApiDefinition(IApiDefinition $definition); * @return OAuth\Tokens\IToken|null */ public function getToken(); + + public function clearToken(); } diff --git a/src/OAuth/TokenStorage/ITokenStorage.php b/src/OAuth/TokenStorage/ITokenStorage.php index 2044931..64d7c9d 100644 --- a/src/OAuth/TokenStorage/ITokenStorage.php +++ b/src/OAuth/TokenStorage/ITokenStorage.php @@ -25,4 +25,11 @@ public function storeToken($key, IToken $token); * @return IToken|null */ public function retrieveToken($key, callable $retrieve = null); + + /** + * Clear the token, forcing revalidation + * + * @param string $key location key for token + */ + public function clearToken($key); } diff --git a/src/OAuth/TokenStorage/MemcachedTokenStorage.php b/src/OAuth/TokenStorage/MemcachedTokenStorage.php index 817569f..cf449ab 100644 --- a/src/OAuth/TokenStorage/MemcachedTokenStorage.php +++ b/src/OAuth/TokenStorage/MemcachedTokenStorage.php @@ -70,4 +70,9 @@ public function retrieveToken($key, callable $retrieve = null) return $token instanceof IToken ? $token : null; } + + public function clearToken($key) + { + $this->_connection->delete($this->_cacheKey($key)); + } } diff --git a/src/OAuth/TokenStorage/TempFileTokenStorage.php b/src/OAuth/TokenStorage/TempFileTokenStorage.php index 7131065..b8cc1f3 100644 --- a/src/OAuth/TokenStorage/TempFileTokenStorage.php +++ b/src/OAuth/TokenStorage/TempFileTokenStorage.php @@ -57,6 +57,12 @@ public function retrieveToken($key, callable $retrieve = null) return $token instanceof IToken ? $token : null; } + public function clearToken($key) + { + $location = $this->_createFileName($key); + unlink($location); + } + /** * Create a temporary filename *