Skip to content

Commit 4a71758

Browse files
committed
Merge pull request #14 from guywithnose/master
Return a resonable message when invalid credentials are passed and add custom client headers
2 parents 51ef324 + a858149 commit 4a71758

3 files changed

Lines changed: 132 additions & 1 deletion

File tree

src/Authentication.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public static function createOwnerCredentials(
114114
public static function parseTokenResponse(Response $response)
115115
{
116116
$parsedJson = $response->getResponse();
117+
Util::ensureNot('invalid_client', Arrays::get($parsedJson, 'error'), 'Invalid Credentials');
117118
Util::ensure(200, $response->getHttpCode(), Arrays::get($parsedJson, 'error_description', 'Unknown API error'));
118119
return [$parsedJson['access_token'], Arrays::get($parsedJson, 'refresh_token'), time() + (int)$parsedJson['expires_in']];
119120
}

src/Client.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ final class Client
9494
*/
9595
private $_handles = [];
9696

97+
/**
98+
* Array of headers that are passed on every request unless they are overridden
99+
*
100+
* @var array
101+
*/
102+
private $_defaultHeaders = [];
103+
97104
/**
98105
* Create a new instance of Client
99106
*
@@ -304,6 +311,18 @@ public function end($handle)
304311
return $response;
305312
}
306313

314+
/**
315+
* Set the default headers
316+
*
317+
* @param array The default headers
318+
*
319+
* @return void
320+
*/
321+
public function setDefaultHeaders($defaultHeaders)
322+
{
323+
$this->_defaultHeaders = $defaultHeaders;
324+
}
325+
307326
private static function _isExpiredToken(Response $response)
308327
{
309328
if ($response->getHttpCode() !== 401) {
@@ -313,9 +332,13 @@ private static function _isExpiredToken(Response $response)
313332
$parsedJson = $response->getResponse();
314333
$error = Arrays::get($parsedJson, 'error');
315334

335+
if (is_array($error)) {
336+
$error = Arrays::get($error, 'code');
337+
}
338+
316339
//This detects expired access tokens on Apigee
317340
if ($error !== null) {
318-
return $error === 'invalid_grant';
341+
return $error === 'invalid_grant' || $error === 'invalid_token';
319342
}
320343

321344
$fault = Arrays::get($parsedJson, 'fault');
@@ -378,6 +401,7 @@ private function _setTokenFromCache()
378401
*/
379402
private function _start($url, $method, $body = null, array $headers = [])
380403
{
404+
$headers += $this->_defaultHeaders;
381405
$headers['Accept-Encoding'] = 'gzip';
382406
if ($this->_accessToken === null) {
383407
$this->_setTokenFromCache();

tests/ClientTest.php

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,66 @@ public function getTokens_withCall()
4545
$this->assertSame([1, null], $client->getTokens());
4646
}
4747

48+
/**
49+
* @test
50+
* @group unit
51+
* @covers ::end
52+
* @uses \DominionEnterprises\Api\Client::startIndex
53+
* @uses \DominionEnterprises\Api\Client::end
54+
* @expectedException Exception
55+
* @expectedExceptionMessage Invalid Credentials
56+
*/
57+
public function exceptionIsThrownOnBadCredentials()
58+
{
59+
$adapter = new AccessTokenInvalidClientAdapter();
60+
$authentication = Authentication::createClientCredentials('not under test', 'not under test');
61+
$client = new Client($adapter, $authentication, 'a url');
62+
$client->end($client->startIndex('a resource', []))->getHttpCode();
63+
}
64+
65+
/**
66+
* @test
67+
* @group unit
68+
* @covers ::end
69+
* @uses \DominionEnterprises\Api\Client::startIndex
70+
* @uses \DominionEnterprises\Api\Client::end
71+
*/
72+
public function invalidTokenIsRefreshed()
73+
{
74+
$adapter = new InvalidAccessTokenAdapter();
75+
$authentication = Authentication::createClientCredentials('not under test', 'not under test');
76+
$client = new Client($adapter, $authentication, 'a url', Client::CACHE_MODE_NONE, null, 'foo');
77+
$this->assertSame(200, $client->end($client->startIndex('a resource', []))->getHttpCode());
78+
}
79+
80+
/**
81+
* @test
82+
* @group unit
83+
* @covers ::setDefaultHeaders
84+
* @uses \DominionEnterprises\Api\Client::setDefaultHeaders
85+
* @uses \DominionEnterprises\Api\Client::startIndex
86+
* @uses \DominionEnterprises\Api\Client::end
87+
*/
88+
public function defaultHeadersArePassed()
89+
{
90+
$adapter = $this->getMockBuilder('\DominionEnterprises\Api\Adapter')->setMethods(['start', 'end'])->getMock();
91+
$adapter->expects($this->once())->method('start')->with(
92+
$this->callback(
93+
function($request) {
94+
$this->assertEquals('foo', $request->getHeaders()['testHeader']);
95+
return true;
96+
}
97+
)
98+
);
99+
$adapter->expects($this->once())->method('end')->will(
100+
$this->returnValue(new Response(200, ['Content-Type' => ['application/json']], []))
101+
);
102+
$authentication = Authentication::createClientCredentials('not under test', 'not under test');
103+
$client = new Client($adapter, $authentication, 'a url', Client::CACHE_MODE_NONE, null, 'foo');
104+
$client->setDefaultHeaders(['testHeader' => 'foo']);
105+
$this->assertSame(200, $client->end($client->startIndex('a resource', []))->getHttpCode());
106+
}
107+
48108
/**
49109
* @test
50110
* @group unit
@@ -691,6 +751,23 @@ public function end($handle)
691751
}
692752
}
693753

754+
final class AccessTokenInvalidClientAdapter implements Adapter
755+
{
756+
private $_request;
757+
758+
public function start(Request $request)
759+
{
760+
$this->_request = $request;
761+
}
762+
763+
public function end($handle)
764+
{
765+
if (substr_count($this->_request->getUrl(), 'token') == 1) {
766+
return new Response(200, ['Content-Type' => ['application/json']], ['error' => 'invalid_client']);
767+
}
768+
}
769+
}
770+
694771
final class AccessTokenAdapter implements Adapter
695772
{
696773
private $_request;
@@ -718,6 +795,35 @@ public function end($handle)
718795
}
719796
}
720797

798+
final class InvalidAccessTokenAdapter implements Adapter
799+
{
800+
private $_request;
801+
private $_count = 0;
802+
803+
public function start(Request $request)
804+
{
805+
$this->_request = $request;
806+
}
807+
808+
public function end($handle)
809+
{
810+
if (substr_count($this->_request->getUrl(), 'token') == 1) {
811+
$response = new Response(200, ['Content-Type' => ['application/json']], ['access_token' => $this->_count, 'expires_in' => 1]);
812+
++$this->_count;
813+
return $response;
814+
}
815+
816+
$headers = $this->_request->getHeaders();
817+
if ($headers['Authorization'] === 'Bearer foo') {
818+
return new Response(401, ['Content-Type' => ['application/json']], ['error' => ['code' => 'invalid_token']]);
819+
} elseif ($headers['Authorization'] === 'Bearer 0') {
820+
return new Response(200, ['Content-Type' => ['application/json']], []);
821+
}
822+
823+
return new Response(401, ['Content-Type' => ['application/json']], ['error' => 'invalid_grant']);
824+
}
825+
}
826+
721827
final class RefreshTokenAdapter implements Adapter
722828
{
723829
private $_request;

0 commit comments

Comments
 (0)