Skip to content

Commit

Permalink
Merge a858149 into 51ef324
Browse files Browse the repository at this point in the history
  • Loading branch information
guywithnose committed Nov 4, 2014
2 parents 51ef324 + a858149 commit ce0c076
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/Authentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public static function createOwnerCredentials(
public static function parseTokenResponse(Response $response)
{
$parsedJson = $response->getResponse();
Util::ensureNot('invalid_client', Arrays::get($parsedJson, 'error'), 'Invalid Credentials');
Util::ensure(200, $response->getHttpCode(), Arrays::get($parsedJson, 'error_description', 'Unknown API error'));
return [$parsedJson['access_token'], Arrays::get($parsedJson, 'refresh_token'), time() + (int)$parsedJson['expires_in']];
}
Expand Down
26 changes: 25 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ final class Client
*/
private $_handles = [];

/**
* Array of headers that are passed on every request unless they are overridden
*
* @var array
*/
private $_defaultHeaders = [];

/**
* Create a new instance of Client
*
Expand Down Expand Up @@ -304,6 +311,18 @@ public function end($handle)
return $response;
}

/**
* Set the default headers
*
* @param array The default headers
*
* @return void
*/
public function setDefaultHeaders($defaultHeaders)
{
$this->_defaultHeaders = $defaultHeaders;
}

private static function _isExpiredToken(Response $response)
{
if ($response->getHttpCode() !== 401) {
Expand All @@ -313,9 +332,13 @@ private static function _isExpiredToken(Response $response)
$parsedJson = $response->getResponse();
$error = Arrays::get($parsedJson, 'error');

if (is_array($error)) {
$error = Arrays::get($error, 'code');
}

//This detects expired access tokens on Apigee
if ($error !== null) {
return $error === 'invalid_grant';
return $error === 'invalid_grant' || $error === 'invalid_token';
}

$fault = Arrays::get($parsedJson, 'fault');
Expand Down Expand Up @@ -378,6 +401,7 @@ private function _setTokenFromCache()
*/
private function _start($url, $method, $body = null, array $headers = [])
{
$headers += $this->_defaultHeaders;
$headers['Accept-Encoding'] = 'gzip';
if ($this->_accessToken === null) {
$this->_setTokenFromCache();
Expand Down
106 changes: 106 additions & 0 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,66 @@ public function getTokens_withCall()
$this->assertSame([1, null], $client->getTokens());
}

/**
* @test
* @group unit
* @covers ::end
* @uses \DominionEnterprises\Api\Client::startIndex
* @uses \DominionEnterprises\Api\Client::end
* @expectedException Exception
* @expectedExceptionMessage Invalid Credentials
*/
public function exceptionIsThrownOnBadCredentials()
{
$adapter = new AccessTokenInvalidClientAdapter();
$authentication = Authentication::createClientCredentials('not under test', 'not under test');
$client = new Client($adapter, $authentication, 'a url');
$client->end($client->startIndex('a resource', []))->getHttpCode();
}

/**
* @test
* @group unit
* @covers ::end
* @uses \DominionEnterprises\Api\Client::startIndex
* @uses \DominionEnterprises\Api\Client::end
*/
public function invalidTokenIsRefreshed()
{
$adapter = new InvalidAccessTokenAdapter();
$authentication = Authentication::createClientCredentials('not under test', 'not under test');
$client = new Client($adapter, $authentication, 'a url', Client::CACHE_MODE_NONE, null, 'foo');
$this->assertSame(200, $client->end($client->startIndex('a resource', []))->getHttpCode());
}

/**
* @test
* @group unit
* @covers ::setDefaultHeaders
* @uses \DominionEnterprises\Api\Client::setDefaultHeaders
* @uses \DominionEnterprises\Api\Client::startIndex
* @uses \DominionEnterprises\Api\Client::end
*/
public function defaultHeadersArePassed()
{
$adapter = $this->getMockBuilder('\DominionEnterprises\Api\Adapter')->setMethods(['start', 'end'])->getMock();
$adapter->expects($this->once())->method('start')->with(
$this->callback(
function($request) {
$this->assertEquals('foo', $request->getHeaders()['testHeader']);
return true;
}
)
);
$adapter->expects($this->once())->method('end')->will(
$this->returnValue(new Response(200, ['Content-Type' => ['application/json']], []))
);
$authentication = Authentication::createClientCredentials('not under test', 'not under test');
$client = new Client($adapter, $authentication, 'a url', Client::CACHE_MODE_NONE, null, 'foo');
$client->setDefaultHeaders(['testHeader' => 'foo']);
$this->assertSame(200, $client->end($client->startIndex('a resource', []))->getHttpCode());
}

/**
* @test
* @group unit
Expand Down Expand Up @@ -691,6 +751,23 @@ public function end($handle)
}
}

final class AccessTokenInvalidClientAdapter implements Adapter
{
private $_request;

public function start(Request $request)
{
$this->_request = $request;
}

public function end($handle)
{
if (substr_count($this->_request->getUrl(), 'token') == 1) {
return new Response(200, ['Content-Type' => ['application/json']], ['error' => 'invalid_client']);
}
}
}

final class AccessTokenAdapter implements Adapter
{
private $_request;
Expand Down Expand Up @@ -718,6 +795,35 @@ public function end($handle)
}
}

final class InvalidAccessTokenAdapter implements Adapter
{
private $_request;
private $_count = 0;

public function start(Request $request)
{
$this->_request = $request;
}

public function end($handle)
{
if (substr_count($this->_request->getUrl(), 'token') == 1) {
$response = new Response(200, ['Content-Type' => ['application/json']], ['access_token' => $this->_count, 'expires_in' => 1]);
++$this->_count;
return $response;
}

$headers = $this->_request->getHeaders();
if ($headers['Authorization'] === 'Bearer foo') {
return new Response(401, ['Content-Type' => ['application/json']], ['error' => ['code' => 'invalid_token']]);
} elseif ($headers['Authorization'] === 'Bearer 0') {
return new Response(200, ['Content-Type' => ['application/json']], []);
}

return new Response(401, ['Content-Type' => ['application/json']], ['error' => 'invalid_grant']);
}
}

final class RefreshTokenAdapter implements Adapter
{
private $_request;
Expand Down

0 comments on commit ce0c076

Please sign in to comment.