From 3adeae0dd6abb2a89b0031e532aa95ca13fa6adb Mon Sep 17 00:00:00 2001 From: Alexey Rakeev Date: Thu, 11 Dec 2014 16:03:56 +0400 Subject: [PATCH 01/13] Added basic state check to workflow example --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7011e21..229c609 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,20 @@ $provider = new League\OAuth2\Client\Provider\(array( 'scopes' => array('email', '...', '...'), )); -if ( ! isset($_GET['code'])) { +if (!isset($_GET['code'])) { // If we don't have an authorization code then get one - header('Location: '.$provider->getAuthorizationUrl()); + $authUrl = $provider->getAuthorizationUrl(); + $_SESSION['oauth2state'] = $provider->state; + header('Location: '.$authUrl); exit; +// Check given state against previously stored one to mitigate CSRF attack +} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { + + unset($_SESSION['oauth2state']); + exit('Invalid state'); + } else { // Try to get an access token (using the authorization code grant) From 188be5bddd4e4614ef4300784d9f617f0dc21491 Mon Sep 17 00:00:00 2001 From: Geoff Date: Wed, 17 Dec 2014 21:15:34 -0600 Subject: [PATCH 02/13] update google scopes and endpoint to remove deprecated values --- src/Provider/Google.php | 21 +++++++++++---------- test/src/Provider/GoogleTest.php | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Provider/Google.php b/src/Provider/Google.php index 5578f2b..cd058d9 100644 --- a/src/Provider/Google.php +++ b/src/Provider/Google.php @@ -9,8 +9,8 @@ class Google extends AbstractProvider public $scopeSeparator = ' '; public $scopes = [ - 'https://www.googleapis.com/auth/userinfo.profile', - 'https://www.googleapis.com/auth/userinfo.email', + 'profile', + 'email', ]; /** @@ -41,7 +41,7 @@ class Google extends AbstractProvider public function urlUserDetails(\League\OAuth2\Client\Token\AccessToken $token) { - return 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token='.$token; + return 'https://www.googleapis.com/plus/v1/people/me?fields=name(familyName%2CgivenName)%2CdisplayName%2Cemails%2Fvalue%2Cimage%2Furl&alt=json&access_token='.$token; } public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token) @@ -50,14 +50,15 @@ class Google extends AbstractProvider $user = new User(); - $imageUrl = (isset($response['picture'])) ? $response['picture'] : null; + $imageUrl = (isset($response['image']) && $response['image']->url) ? $response['image']->url : null; + $email = (isset($response['emails']) && count($response['emails']) && $response['emails'][0]->value)? $response['emails'][0]->value : null; $user->exchangeArray([ 'uid' => $response['id'], - 'name' => $response['name'], - 'firstname' => $response['given_name'], - 'lastName' => $response['family_name'], - 'email' => $response['email'], + 'name' => $response['displayName'], + 'firstname' => $response['name']->givenName, + 'lastName' => $response['name']->familyName, + 'email' => $email, 'imageUrl' => $imageUrl, ]); @@ -71,12 +72,12 @@ class Google extends AbstractProvider public function userEmail($response, \League\OAuth2\Client\Token\AccessToken $token) { - return isset($response->email) && $response->email ? $response->email : null; + return ($response->emails && count($response->emails) && $response->emails[0]->value) ? $response->emails[0]->value : null; } public function userScreenName($response, \League\OAuth2\Client\Token\AccessToken $token) { - return [$response->given_name, $response->family_name]; + return [$response->name->givenName, $response->name->familyName]; } public function getAuthorizationUrl($options = array()) diff --git a/test/src/Provider/GoogleTest.php b/test/src/Provider/GoogleTest.php index bfb0810..235b426 100644 --- a/test/src/Provider/GoogleTest.php +++ b/test/src/Provider/GoogleTest.php @@ -71,7 +71,7 @@ class GoogleTest extends \PHPUnit_Framework_TestCase public function testScopes() { - $this->assertEquals(['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'], $this->provider->getScopes()); + $this->assertEquals(['profile', 'email'], $this->provider->getScopes()); } public function testUserData() @@ -80,7 +80,7 @@ class GoogleTest extends \PHPUnit_Framework_TestCase $postResponse->shouldReceive('getBody')->times(1)->andReturn('{"access_token": "mock_access_token", "expires": 3600, "refresh_token": "mock_refresh_token", "uid": 1}'); $getResponse = m::mock('Guzzle\Http\Message\Response'); - $getResponse->shouldReceive('getBody')->times(4)->andReturn('{"id": 12345, "name": "mock_name", "given_name": "mock_first_name", "family_name": "mock_last_name", "email": "mock_email"}'); + $getResponse->shouldReceive('getBody')->times(4)->andReturn('{"emails": [{"value": "mock_email"}],"id": "12345","displayName": "mock_name","name": {"familyName": "mock_last_name","givenName": "mock_first_name"},"image": {"url": "mock_image_url"}}'); $client = m::mock('Guzzle\Service\Client'); $client->shouldReceive('setBaseUrl')->times(5); From 04d64d76b50a0012ea1c4e2bf799d10b42cb614a Mon Sep 17 00:00:00 2001 From: Geoff Date: Wed, 17 Dec 2014 21:27:33 -0600 Subject: [PATCH 03/13] fixed long lines --- src/Provider/Google.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Provider/Google.php b/src/Provider/Google.php index cd058d9..225e508 100644 --- a/src/Provider/Google.php +++ b/src/Provider/Google.php @@ -41,7 +41,10 @@ class Google extends AbstractProvider public function urlUserDetails(\League\OAuth2\Client\Token\AccessToken $token) { - return 'https://www.googleapis.com/plus/v1/people/me?fields=name(familyName%2CgivenName)%2CdisplayName%2Cemails%2Fvalue%2Cimage%2Furl&alt=json&access_token='.$token; + return + 'https://www.googleapis.com/plus/v1/people/me?'. + 'fields=name(familyName%2CgivenName)%2CdisplayName%2C'. + 'emails%2Fvalue%2Cimage%2Furl&alt=json&access_token='.$token; } public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token) @@ -50,8 +53,12 @@ class Google extends AbstractProvider $user = new User(); - $imageUrl = (isset($response['image']) && $response['image']->url) ? $response['image']->url : null; - $email = (isset($response['emails']) && count($response['emails']) && $response['emails'][0]->value)? $response['emails'][0]->value : null; + $imageUrl = (isset($response['image']) && + $response['image']->url) ? $response['image']->url : null; + $email = + (isset($response['emails']) && + count($response['emails']) && + $response['emails'][0]->value)? $response['emails'][0]->value : null; $user->exchangeArray([ 'uid' => $response['id'], @@ -72,7 +79,9 @@ class Google extends AbstractProvider public function userEmail($response, \League\OAuth2\Client\Token\AccessToken $token) { - return ($response->emails && count($response->emails) && $response->emails[0]->value) ? $response->emails[0]->value : null; + return ($response->emails && + count($response->emails) && + $response->emails[0]->value) ? $response->emails[0]->value : null; } public function userScreenName($response, \League\OAuth2\Client\Token\AccessToken $token) From 5952f5d8f56904ab7a19519c5add6cca1f09304b Mon Sep 17 00:00:00 2001 From: Geoff Lancaster Date: Sun, 21 Dec 2014 23:02:09 -0600 Subject: [PATCH 04/13] updated spaces --- src/Provider/Google.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Provider/Google.php b/src/Provider/Google.php index 225e508..30f5392 100644 --- a/src/Provider/Google.php +++ b/src/Provider/Google.php @@ -42,9 +42,9 @@ class Google extends AbstractProvider public function urlUserDetails(\League\OAuth2\Client\Token\AccessToken $token) { return - 'https://www.googleapis.com/plus/v1/people/me?'. - 'fields=name(familyName%2CgivenName)%2CdisplayName%2C'. - 'emails%2Fvalue%2Cimage%2Furl&alt=json&access_token='.$token; + 'https://www.googleapis.com/plus/v1/people/me?'. + 'fields=name(familyName%2CgivenName)%2CdisplayName%2C'. + 'emails%2Fvalue%2Cimage%2Furl&alt=json&access_token='.$token; } public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token) @@ -54,11 +54,11 @@ class Google extends AbstractProvider $user = new User(); $imageUrl = (isset($response['image']) && - $response['image']->url) ? $response['image']->url : null; + $response['image']->url) ? $response['image']->url : null; $email = - (isset($response['emails']) && - count($response['emails']) && - $response['emails'][0]->value)? $response['emails'][0]->value : null; + (isset($response['emails']) && + count($response['emails']) && + $response['emails'][0]->value)? $response['emails'][0]->value : null; $user->exchangeArray([ 'uid' => $response['id'], @@ -80,8 +80,8 @@ class Google extends AbstractProvider public function userEmail($response, \League\OAuth2\Client\Token\AccessToken $token) { return ($response->emails && - count($response->emails) && - $response->emails[0]->value) ? $response->emails[0]->value : null; + count($response->emails) && + $response->emails[0]->value) ? $response->emails[0]->value : null; } public function userScreenName($response, \League\OAuth2\Client\Token\AccessToken $token) From 65810afe06db548c74d5041f5e96f6da55afa363 Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Tue, 23 Dec 2014 16:16:50 +0100 Subject: [PATCH 05/13] Added support for Github Enterprise --- src/Provider/Github.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Provider/Github.php b/src/Provider/Github.php index 1ef473c..009c5d8 100644 --- a/src/Provider/Github.php +++ b/src/Provider/Github.php @@ -8,19 +8,24 @@ class Github extends AbstractProvider { public $responseType = 'string'; + public $domain = 'https://github.com'; + public function urlAuthorize() { - return 'https://github.com/login/oauth/authorize'; + return $this->domain.'/login/oauth/authorize'; } public function urlAccessToken() { - return 'https://github.com/login/oauth/access_token'; + return $this->domain.'/login/oauth/access_token'; } public function urlUserDetails(\League\OAuth2\Client\Token\AccessToken $token) { - return 'https://api.github.com/user?access_token='.$token; + if ($this->domain == 'https://github.com') { + return $this->domain.'/user?access_token='.$token; + } + return $this->domain.'/api/v3/user?access_token='.$token; } public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token) @@ -36,7 +41,7 @@ class Github extends AbstractProvider 'name' => $name, 'email' => $email, 'urls' => [ - 'GitHub' => 'http://github.com/'.$response->login, + 'GitHub' => $this->domain.'/'.$response->login, ], ]); From 3df7382ee184a8e0726953e766446906113f9f7a Mon Sep 17 00:00:00 2001 From: Sergio Vera Date: Tue, 23 Dec 2014 17:25:56 +0100 Subject: [PATCH 06/13] Added tests --- test/src/Provider/GithubTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/src/Provider/GithubTest.php b/test/src/Provider/GithubTest.php index 5db808c..4ca85f9 100644 --- a/test/src/Provider/GithubTest.php +++ b/test/src/Provider/GithubTest.php @@ -114,4 +114,22 @@ class GithubTest extends \PHPUnit_Framework_TestCase $this->assertEquals('mock_name', $user->name); $this->assertEquals('mock_email', $this->provider->getUserEmail($token)); } + + public function testGithubEnterpriseDomainUrls() + { + $this->provider->domain = 'https://github.company.com'; + + $client = m::mock('Guzzle\Service\Client'); + $response = m::mock('Guzzle\Http\Message\Response'); + $response->shouldReceive('getBody')->times(1)->andReturn('access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&otherKey={1234}'); + + $client->shouldReceive('setBaseUrl')->times(1); + $client->shouldReceive('post->send')->times(1)->andReturn($response); + $this->provider->setHttpClient($client); + $token = $this->provider->getAccessToken('authorization_code', ['code' => 'mock_authorization_code']); + + $this->assertEquals($this->provider->domain.'/login/oauth/authorize', $this->provider->urlAuthorize()); + $this->assertEquals($this->provider->domain.'/login/oauth/access_token', $this->provider->urlAccessToken()); + $this->assertEquals($this->provider->domain.'/api/v3/user?access_token=mock_access_token', $this->provider->urlUserDetails($token)); + } } From 91ec971a7395930f6d8f2c8bee9da3f9a190fa9d Mon Sep 17 00:00:00 2001 From: SangYeob Bono Yu Date: Mon, 29 Dec 2014 15:07:37 +0900 Subject: [PATCH 07/13] Added Naver as Third-Party Provider --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9000423..1117cb3 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ so please help them out with a pull request if you notice this. - [Odnoklassniki](https://packagist.org/packages/aego/oauth2-odnoklassniki) - [Yandex](https://packagist.org/packages/aego/oauth2-yandex) - [Vkontakte](https://packagist.org/packages/j4k/oauth2-vkontakte) +- [Naver](https://packagist.org/packages/deminoth/oauth2-naver) ### Implementing your own provider From 0d25e02de79d66b0e937dad7504d3cb4159cb943 Mon Sep 17 00:00:00 2001 From: jeremykendall Date: Tue, 23 Dec 2014 14:33:55 -0600 Subject: [PATCH 08/13] Adds AbstractProvider::fetchProviderData(). New protected method is responsible for making the request to a provided URL, allowing for multiple API endpoints to be used within the same provider. AbstractProvider::fetchUserDetails() remains, but now only builds the user details URL and passes it to AbstractProvider::fetchProviderData(). --- src/Provider/AbstractProvider.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Provider/AbstractProvider.php b/src/Provider/AbstractProvider.php index 3ca4aa8..6eab5a3 100644 --- a/src/Provider/AbstractProvider.php +++ b/src/Provider/AbstractProvider.php @@ -311,6 +311,11 @@ abstract class AbstractProvider implements ProviderInterface { $url = $this->urlUserDetails($token); + return $this->fetchProviderData($url); + } + + protected function fetchProviderData($url) + { try { $client = $this->getHttpClient(); $client->setBaseUrl($url); @@ -331,6 +336,7 @@ abstract class AbstractProvider implements ProviderInterface return $response; } + public function setRedirectHandler(Closure $handler) { $this->redirectHandler = $handler; From 8c0ae57065ae6da5c7d00217f948b269615fa75b Mon Sep 17 00:00:00 2001 From: jeremykendall Date: Tue, 23 Dec 2014 14:37:03 -0600 Subject: [PATCH 09/13] Adds methods that fetch a Github user's email addresses. --- src/Provider/Github.php | 24 ++++++++++++++++++++++++ test/src/Provider/GithubTest.php | 22 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/Provider/Github.php b/src/Provider/Github.php index 009c5d8..5631ab8 100644 --- a/src/Provider/Github.php +++ b/src/Provider/Github.php @@ -28,6 +28,11 @@ class Github extends AbstractProvider return $this->domain.'/api/v3/user?access_token='.$token; } + public function urlUserEmails(\League\OAuth2\Client\Token\AccessToken $token) + { + return 'https://api.github.com/user/emails?access_token='.$token; + } + public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token) { $user = new User(); @@ -53,13 +58,32 @@ class Github extends AbstractProvider return $response->id; } + public function getUserEmails(\League\OAuth2\Client\Token\AccessToken $token) + { + $response = $this->fetchUserEmails($token); + + return $this->userEmails(json_decode($response), $token); + } + public function userEmail($response, \League\OAuth2\Client\Token\AccessToken $token) { return isset($response->email) && $response->email ? $response->email : null; } + public function userEmails($response, \League\OAuth2\Client\Token\AccessToken $token) + { + return $response; + } + public function userScreenName($response, \League\OAuth2\Client\Token\AccessToken $token) { return $response->name; } + + protected function fetchUserEmails(\League\OAuth2\Client\Token\AccessToken $token) + { + $url = $this->urlUserEmails($token); + + return $this->fetchProviderData($url); + } } diff --git a/test/src/Provider/GithubTest.php b/test/src/Provider/GithubTest.php index 4ca85f9..1e6c0e2 100644 --- a/test/src/Provider/GithubTest.php +++ b/test/src/Provider/GithubTest.php @@ -132,4 +132,26 @@ class GithubTest extends \PHPUnit_Framework_TestCase $this->assertEquals($this->provider->domain.'/login/oauth/access_token', $this->provider->urlAccessToken()); $this->assertEquals($this->provider->domain.'/api/v3/user?access_token=mock_access_token', $this->provider->urlUserDetails($token)); } + + public function testUserEmails() + { + $postResponse = m::mock('Guzzle\Http\Message\Response'); + $postResponse->shouldReceive('getBody')->times(1)->andReturn('access_token=mock_access_token&expires=3600&refresh_token=mock_refresh_token&uid=1'); + + $getResponse = m::mock('Guzzle\Http\Message\Response'); + $getResponse->shouldReceive('getBody')->times(1)->andReturn('[{"email":"mock_email_1","primary":false,"verified":true},{"email":"mock_email_2","primary":false,"verified":true},{"email":"mock_email_3","primary":true,"verified":true}]'); + + $client = m::mock('Guzzle\Service\Client'); + $client->shouldReceive('setBaseUrl')->times(2); + $client->shouldReceive('post->send')->times(1)->andReturn($postResponse); + $client->shouldReceive('get->send')->times(1)->andReturn($getResponse); + $this->provider->setHttpClient($client); + + $token = $this->provider->getAccessToken('authorization_code', ['code' => 'mock_authorization_code']); + $emails = $this->provider->getUserEmails($token); + $this->assertInternalType('array', $emails); + $this->assertCount(3, $emails); + $this->assertEquals('mock_email_3', $emails[2]->email); + $this->assertTrue($emails[2]->primary); + } } From f3d6724d6c03631708ba26f5176ebe4f3ef0b733 Mon Sep 17 00:00:00 2001 From: jeremykendall Date: Mon, 29 Dec 2014 04:18:12 -0600 Subject: [PATCH 10/13] Updates string comparison to use identical operator --- src/Provider/Github.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Provider/Github.php b/src/Provider/Github.php index 5631ab8..50124da 100644 --- a/src/Provider/Github.php +++ b/src/Provider/Github.php @@ -22,7 +22,7 @@ class Github extends AbstractProvider public function urlUserDetails(\League\OAuth2\Client\Token\AccessToken $token) { - if ($this->domain == 'https://github.com') { + if ($this->domain === 'https://github.com') { return $this->domain.'/user?access_token='.$token; } return $this->domain.'/api/v3/user?access_token='.$token; From 831f329e1c8ecd7a9ea283c72dac37ca530b7f0f Mon Sep 17 00:00:00 2001 From: jeremykendall Date: Mon, 29 Dec 2014 04:18:33 -0600 Subject: [PATCH 11/13] Updates urlEmailEquals for use with Github Enterprise See #188. --- src/Provider/Github.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Provider/Github.php b/src/Provider/Github.php index 50124da..b78727b 100644 --- a/src/Provider/Github.php +++ b/src/Provider/Github.php @@ -30,7 +30,10 @@ class Github extends AbstractProvider public function urlUserEmails(\League\OAuth2\Client\Token\AccessToken $token) { - return 'https://api.github.com/user/emails?access_token='.$token; + if ($this->domain === 'https://github.com') { + return $this->domain.'/user/emails?access_token='.$token; + } + return $this->domain.'/api/v3/user/emails?access_token='.$token; } public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token) From 63d4bc6d941a98cae0c347947dd9e53def5de8a4 Mon Sep 17 00:00:00 2001 From: jeremykendall Date: Mon, 29 Dec 2014 04:19:32 -0600 Subject: [PATCH 12/13] Adds emails endpoint to GithubTest::testGithubEnterpriseDomainUrls --- test/src/Provider/GithubTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/Provider/GithubTest.php b/test/src/Provider/GithubTest.php index 1e6c0e2..c0843ca 100644 --- a/test/src/Provider/GithubTest.php +++ b/test/src/Provider/GithubTest.php @@ -131,6 +131,7 @@ class GithubTest extends \PHPUnit_Framework_TestCase $this->assertEquals($this->provider->domain.'/login/oauth/authorize', $this->provider->urlAuthorize()); $this->assertEquals($this->provider->domain.'/login/oauth/access_token', $this->provider->urlAccessToken()); $this->assertEquals($this->provider->domain.'/api/v3/user?access_token=mock_access_token', $this->provider->urlUserDetails($token)); + $this->assertEquals($this->provider->domain.'/api/v3/user/emails?access_token=mock_access_token', $this->provider->urlUserEmails($token)); } public function testUserEmails() From 1d790ed19d49e5da8b0c431eb84797f3eec5fd36 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Mon, 29 Dec 2014 06:01:20 -0500 Subject: [PATCH 13/13] Updating Composer branch alias for master to 0.7.x-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d9fe5af..195a1ed 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } }