Skip to content

Decouple from Guzzle #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
language: php

php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ so please help them out with a pull request if you notice this.
Via Composer

```shell
$ composer require league/oauth1-client
$ composer require league/oauth1-client php-http/message php-http/guzzle6-adapter
```

We are not coupled to any library sending HTTP messages. We use an abstraction called
HTTPlug that allows you to choose the client you want. Read more about it
[in the docs](http://docs.php-http.org/en/latest/httplug/users.html).

## Usage

Expand Down
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
"license": "MIT",
"require": {
"php": ">=5.5.0",
"guzzlehttp/guzzle": "^6.0"
"php-http/httplug": "^1.0",
"php-http/discovery": "^1.0",
"psr/http-message-implementation": "^1.0",
"php-http/client-implementation": "^1.0"
},
"require-dev": {
"php-http/message": "^1.0",
"php-http/guzzle6-adapter": "^1.0",
"phpunit/phpunit": "^4.0",
"mockery/mockery": "^0.9",
"squizlabs/php_codesniffer": "^2.0"
Expand Down
70 changes: 32 additions & 38 deletions src/Client/Server/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace League\OAuth1\Client\Server;

use GuzzleHttp\Client as GuzzleHttpClient;
use GuzzleHttp\Exception\BadResponseException;
use Http\Client\HttpClient;
use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use League\OAuth1\Client\Credentials\ClientCredentialsInterface;
use League\OAuth1\Client\Credentials\ClientCredentials;
use League\OAuth1\Client\Credentials\CredentialsInterface;
Expand All @@ -12,6 +13,7 @@
use League\OAuth1\Client\Credentials\TokenCredentials;
use League\OAuth1\Client\Signature\HmacSha1Signature;
use League\OAuth1\Client\Signature\SignatureInterface;
use Psr\Http\Message\ResponseInterface;

abstract class Server
{
Expand Down Expand Up @@ -79,18 +81,16 @@ public function getTemporaryCredentials()
{
$uri = $this->urlTemporaryCredentials();

$client = $this->createHttpClient();

$header = $this->temporaryCredentialsProtocolHeader($uri);
$authorizationHeader = array('Authorization' => $header);
$headers = $this->buildHttpClientHeaders($authorizationHeader);

try {
$response = $client->post($uri, [
'headers' => $headers,
]);
} catch (BadResponseException $e) {
return $this->handleTemporaryCredentialsBadResponse($e);
$request = MessageFactoryDiscovery::find()->createRequest('POST', $uri, $headers);
$response = $this->createHttpClient()->sendRequest($request);
$statusCode = $response->getStatusCode();

if ($statusCode >= 400 && $statusCode < 600) {
$this->handleTemporaryCredentialsBadResponse($response);
}

return $this->createTemporaryCredentials((string) $response->getBody());
Expand Down Expand Up @@ -157,17 +157,16 @@ public function getTokenCredentials(TemporaryCredentials $temporaryCredentials,
$uri = $this->urlTokenCredentials();
$bodyParameters = array('oauth_verifier' => $verifier);

$client = $this->createHttpClient();

$headers = $this->getHeaders($temporaryCredentials, 'POST', $uri, $bodyParameters);
$headers['Content-Type'] = 'application/x-www-form-urlencoded';

try {
$response = $client->post($uri, [
'headers' => $headers,
'form_params' => $bodyParameters,
]);
} catch (BadResponseException $e) {
return $this->handleTokenCredentialsBadResponse($e);
$request = MessageFactoryDiscovery::find()
->createRequest('POST', $uri, $headers, http_build_query($bodyParameters));
$response = $this->createHttpClient()->sendRequest($request);
$statusCode = $response->getStatusCode();

if ($statusCode >= 400 && $statusCode < 600) {
$this->handleTokenCredentialsBadResponse($response);
}

return $this->createTokenCredentials((string) $response->getBody());
Expand Down Expand Up @@ -246,23 +245,20 @@ protected function fetchUserDetails(TokenCredentials $tokenCredentials, $force =
if (!$this->cachedUserDetailsResponse || $force) {
$url = $this->urlUserDetails();

$client = $this->createHttpClient();

$headers = $this->getHeaders($tokenCredentials, 'GET', $url);
$request = MessageFactoryDiscovery::find()->createRequest('GET', $url, $headers);
$response = $this->createHttpClient()->sendRequest($request);
$statusCode = $response->getStatusCode();

try {
$response = $client->get($url, [
'headers' => $headers,
]);
} catch (BadResponseException $e) {
$response = $e->getResponse();
if ($statusCode >= 400 && $statusCode < 600) {
$body = $response->getBody();
$statusCode = $response->getStatusCode();

throw new \Exception(
"Received error [$body] with status code [$statusCode] when retrieving token credentials."
);
}

switch ($this->responseType) {
case 'json':
$this->cachedUserDetailsResponse = json_decode((string) $response->getBody(), true);
Expand Down Expand Up @@ -305,13 +301,13 @@ public function getSignature()
}

/**
* Creates a Guzzle HTTP client for the given URL.
* Creates a HTTP client
*
* @return GuzzleHttpClient
* @return HttpClient
*/
public function createHttpClient()
{
return new GuzzleHttpClient();
return HttpClientDiscovery::find();
}

/**
Expand Down Expand Up @@ -348,7 +344,7 @@ public function getHeaders(CredentialsInterface $credentials, $method, $url, arr
}

/**
* Get Guzzle HTTP client default headers.
* Get HTTP client default headers.
*
* @return array
*/
Expand All @@ -363,7 +359,7 @@ protected function getHttpClientDefaultHeaders()
}

/**
* Build Guzzle HTTP client headers.
* Build HTTP headers.
*
* @return array
*/
Expand Down Expand Up @@ -405,13 +401,12 @@ protected function createClientCredentials(array $clientCredentials)
/**
* Handle a bad response coming back when getting temporary credentials.
*
* @param BadResponseException $e
* @param ResponseInterface $response
*
* @throws CredentialsException
*/
protected function handleTemporaryCredentialsBadResponse(BadResponseException $e)
protected function handleTemporaryCredentialsBadResponse(ResponseInterface $response)
{
$response = $e->getResponse();
$body = $response->getBody();
$statusCode = $response->getStatusCode();

Expand Down Expand Up @@ -449,13 +444,12 @@ protected function createTemporaryCredentials($body)
/**
* Handle a bad response coming back when getting token credentials.
*
* @param BadResponseException $e
* @param ResponseInterface $response
*
* @throws CredentialsException
*/
protected function handleTokenCredentialsBadResponse(BadResponseException $e)
protected function handleTokenCredentialsBadResponse(ResponseInterface $response)
{
$response = $e->getResponse();
$body = $response->getBody();
$statusCode = $response->getStatusCode();

Expand Down
21 changes: 8 additions & 13 deletions src/Client/Signature/HmacSha1Signature.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace League\OAuth1\Client\Signature;

use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Uri;
use Http\Discovery\UriFactoryDiscovery;
use Psr\Http\Message\UriInterface;

class HmacSha1Signature extends Signature implements SignatureInterface
{
Expand All @@ -28,36 +28,31 @@ public function sign($uri, array $parameters = array(), $method = 'POST')
}

/**
* Create a Guzzle url for the given URI.
* Create a PSR URI for the given string URI.
*
* @param string $uri
*
* @return Url
* @return UriInterface
*/
protected function createUrl($uri)
{
return Psr7\uri_for($uri);
return UriFactoryDiscovery::find()->createUri($uri);
}

/**
* Generate a base string for a HMAC-SHA1 signature
* based on the given a url, method, and any parameters.
*
* @param Url $url
* @param UriInterface $url
* @param string $method
* @param array $parameters
*
* @return string
*/
protected function baseString(Uri $url, $method = 'POST', array $parameters = array())
protected function baseString(UriInterface $url, $method = 'POST', array $parameters = array())
{
$baseString = rawurlencode($method).'&';

$schemeHostPath = Uri::fromParts(array(
'scheme' => $url->getScheme(),
'host' => $url->getHost(),
'path' => $url->getPath(),
));
$schemeHostPath = $this->createUrl(sprintf('%s://%s%s', $url->getScheme(), $url->getHost(), $url->getPath()));

$baseString .= rawurlencode($schemeHostPath).'&';

Expand Down
57 changes: 32 additions & 25 deletions tests/ServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
* @link http://cartalyst.com
*/

use GuzzleHttp\Psr7\Response;
use League\OAuth1\Client\Credentials\ClientCredentials;
use Mockery as m;
use PHPUnit_Framework_TestCase;
use Psr\Http\Message\RequestInterface;

class ServerTest extends PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -82,8 +84,11 @@ public function testGettingTemporaryCredentials()
$server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass'));

$me = $this;
$client->shouldReceive('post')->with('http://www.example.com/temporary', m::on(function($options) use ($me) {
$headers = $options['headers'];
$client->shouldReceive('sendRequest')->with(m::on(function(RequestInterface $request) use ($me) {
$headers = $request->getHeaders();
$uri = $request->getUri()->__toString();
$me->assertSame($uri, 'http://www.example.com/temporary');


$me->assertTrue(isset($headers['Authorization']));

Expand All @@ -92,12 +97,11 @@ public function testGettingTemporaryCredentials()
// We'll validate that here.
$pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_callback="'.preg_quote('http%3A%2F%2Fapp.dev%2F', '/').'", oauth_signature=".*?"/';

$matches = preg_match($pattern, $headers['Authorization']);
$matches = preg_match($pattern, $headers['Authorization'][0]);
$me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.');

return true;
}))->once()->andReturn($response = m::mock('stdClass'));
$response->shouldReceive('getBody')->andReturn('oauth_token=temporarycredentialsidentifier&oauth_token_secret=temporarycredentialssecret&oauth_callback_confirmed=true');
}))->once()->andReturn(new Response(200, [], 'oauth_token=temporarycredentialsidentifier&oauth_token_secret=temporarycredentialssecret&oauth_callback_confirmed=true'));

$credentials = $server->getTemporaryCredentials();
$this->assertInstanceOf('League\OAuth1\Client\Credentials\TemporaryCredentials', $credentials);
Expand Down Expand Up @@ -142,9 +146,10 @@ public function testGettingTokenCredentials()
$server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass'));

$me = $this;
$client->shouldReceive('post')->with('http://www.example.com/token', m::on(function($options) use ($me) {
$headers = $options['headers'];
$body = $options['form_params'];
$client->shouldReceive('sendRequest')->with(m::on(function(RequestInterface $request) use ($me) {
$headers = $request->getHeaders();
$uri = $request->getUri()->__toString();
$body = $request->getBody()->__toString();

$me->assertTrue(isset($headers['Authorization']));
$me->assertFalse(isset($headers['User-Agent']));
Expand All @@ -154,14 +159,14 @@ public function testGettingTokenCredentials()
// We'll validate that here.
$pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="temporarycredentialsidentifier", oauth_signature=".*?"/';

$matches = preg_match($pattern, $headers['Authorization']);
$matches = preg_match($pattern, $headers['Authorization'][0]);
$me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.');

$me->assertSame($body, array('oauth_verifier' => 'myverifiercode'));
$me->assertSame($body, http_build_query(array('oauth_verifier' => 'myverifiercode')));
$me->assertSame($uri, 'http://www.example.com/token');

return true;
}))->once()->andReturn($response = m::mock('stdClass'));
$response->shouldReceive('getBody')->andReturn('oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret');
}))->once()->andReturn(new Response(200, [], 'oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret'));

$credentials = $server->getTokenCredentials($temporaryCredentials, 'temporarycredentialsidentifier', 'myverifiercode');
$this->assertInstanceOf('League\OAuth1\Client\Credentials\TokenCredentials', $credentials);
Expand All @@ -181,27 +186,28 @@ public function testGettingTokenCredentialsWithUserAgent()
$server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass'));

$me = $this;
$client->shouldReceive('post')->with('http://www.example.com/token', m::on(function($options) use ($me, $userAgent) {
$headers = $options['headers'];
$body = $options['form_params'];
$client->shouldReceive('sendRequest')->with(m::on(function(RequestInterface $request) use ($me, $userAgent) {
$headers = $request->getHeaders();
$uri = $request->getUri()->__toString();
$body = $request->getBody()->__toString();

$me->assertTrue(isset($headers['Authorization']));
$me->assertTrue(isset($headers['User-Agent']));
$me->assertEquals($userAgent, $headers['User-Agent']);
$me->assertEquals($userAgent, $headers['User-Agent'][0]);

// OAuth protocol specifies a strict number of
// headers should be sent, in the correct order.
// We'll validate that here.
$pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="temporarycredentialsidentifier", oauth_signature=".*?"/';

$matches = preg_match($pattern, $headers['Authorization']);
$matches = preg_match($pattern, $headers['Authorization'][0]);
$me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.');

$me->assertSame($body, array('oauth_verifier' => 'myverifiercode'));
$me->assertSame($body, http_build_query(array('oauth_verifier' => 'myverifiercode')));
$me->assertSame($uri, 'http://www.example.com/token');

return true;
}))->once()->andReturn($response = m::mock('stdClass'));
$response->shouldReceive('getBody')->andReturn('oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret');
}))->once()->andReturn(new Response(200, [], 'oauth_token=tokencredentialsidentifier&oauth_token_secret=tokencredentialssecret'));

$credentials = $server->setUserAgent($userAgent)->getTokenCredentials($temporaryCredentials, 'temporarycredentialsidentifier', 'myverifiercode');
$this->assertInstanceOf('League\OAuth1\Client\Credentials\TokenCredentials', $credentials);
Expand All @@ -221,8 +227,10 @@ public function testGettingUserDetails()
$server->shouldReceive('createHttpClient')->andReturn($client = m::mock('stdClass'));

$me = $this;
$client->shouldReceive('get')->with('http://www.example.com/user', m::on(function($options) use ($me) {
$headers = $options['headers'];
$client->shouldReceive('sendRequest')->with(m::on(function(RequestInterface $request) use ($me) {
$headers = $request->getHeaders();
$url = $request->getUri()->__toString();
$me->assertSame('http://www.example.com/user', $url);

$me->assertTrue(isset($headers['Authorization']));

Expand All @@ -231,12 +239,11 @@ public function testGettingUserDetails()
// We'll validate that here.
$pattern = '/OAuth oauth_consumer_key=".*?", oauth_nonce="[a-zA-Z0-9]+", oauth_signature_method="HMAC-SHA1", oauth_timestamp="\d{10}", oauth_version="1.0", oauth_token="tokencredentialsidentifier", oauth_signature=".*?"/';

$matches = preg_match($pattern, $headers['Authorization']);
$matches = preg_match($pattern, $headers['Authorization'][0]);
$me->assertEquals(1, $matches, 'Asserting that the authorization header contains the correct expression.');

return true;
}))->once()->andReturn($response = m::mock('stdClass'));
$response->shouldReceive('getBody')->once()->andReturn(json_encode(array('foo' => 'bar', 'id' => 123, 'contact_email' => '[email protected]', 'username' => 'fred')));
}))->once()->andReturn(new Response(200, [], json_encode(array('foo' => 'bar', 'id' => 123, 'contact_email' => '[email protected]', 'username' => 'fred'))));

$user = $server->getUserDetails($temporaryCredentials);
$this->assertInstanceOf('League\OAuth1\Client\Server\User', $user);
Expand Down
Loading