Merge branch 'master' into 1.0

Conflicts:
	test/src/Provider/GoogleTest.php
1.0
Ben Ramsey 2014-12-29 06:09:55 -05:00
commit 30d9b47e8d
7 changed files with 117 additions and 19 deletions

View File

@ -42,12 +42,20 @@ $provider = new League\OAuth2\Client\Provider\<ProviderName>(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)
@ -130,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

View File

@ -41,7 +41,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "0.6.x-dev"
"dev-master": "0.7.x-dev"
}
}
}

View File

@ -315,6 +315,11 @@ abstract class AbstractProvider implements ProviderInterface
{
$url = $this->urlUserDetails($token);
return $this->fetchProviderData($url);
}
protected function fetchProviderData($url)
{
try {
$client = $this->getHttpClient();
@ -336,6 +341,7 @@ abstract class AbstractProvider implements ProviderInterface
return $response;
}
public function setRedirectHandler(Closure $handler)
{
$this->redirectHandler = $handler;

View File

@ -8,19 +8,32 @@ 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 urlUserEmails(\League\OAuth2\Client\Token\AccessToken $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)
@ -36,7 +49,7 @@ class Github extends AbstractProvider
'name' => $name,
'email' => $email,
'urls' => [
'GitHub' => 'http://github.com/'.$response->login,
'GitHub' => $this->domain.'/'.$response->login,
],
]);
@ -48,13 +61,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);
}
}

View File

@ -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,10 @@ 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%2C'.
'emails%2Fvalue%2Cimage%2Furl&alt=json&access_token='.$token;
}
public function userDetails($response, \League\OAuth2\Client\Token\AccessToken $token)
@ -50,14 +53,19 @@ 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 +79,14 @@ 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())

View File

@ -111,4 +111,45 @@ 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));
$this->assertEquals($this->provider->domain.'/api/v3/user/emails?access_token=mock_access_token', $this->provider->urlUserEmails($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);
}
}

View File

@ -70,7 +70,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()
@ -79,7 +79,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('GuzzleHttp\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('GuzzleHttp\Client');
$client->shouldReceive('post')->times(1)->andReturn($postResponse);