Update Laravel socailite package

Update Laravel socailite package to fix facebook authentication.
This commit is contained in:
Manish Verma
2018-08-16 14:47:19 +05:30
parent cfec60b43f
commit 89809c3123
50 changed files with 647 additions and 361 deletions

View File

@@ -1,5 +0,0 @@
/vendor
composer.phar
composer.lock
.DS_Store
Thumbs.db

View File

@@ -1,13 +0,0 @@
language: php
php:
- 5.6
- 7.0
- 7.1
- hhvm
sudo: false
install: travis_retry composer install --no-interaction --prefer-source
script: vendor/bin/phpunit --verbose

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) <Taylor Otwell>
Copyright (c) Taylor Otwell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -6,31 +6,47 @@
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
"email": "taylor@laravel.com"
}
],
"require": {
"php": ">=5.4.0",
"guzzlehttp/guzzle": "~6.0",
"illuminate/contracts": "~5.4",
"illuminate/http": "~5.4",
"illuminate/support": "~5.4",
"guzzlehttp/guzzle": "~6.0",
"league/oauth1-client": "~1.0"
},
"require-dev": {
"mockery/mockery": "~0.9",
"phpunit/phpunit": "~4.0"
"phpunit/phpunit": "~4.0|~5.0"
},
"autoload": {
"psr-4": {
"Laravel\\Socialite\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
},
"laravel": {
"providers": [
"Laravel\\Socialite\\SocialiteServiceProvider"
],
"aliases": {
"Socialite": "Laravel\\Socialite\\Facades\\Socialite"
}
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@@ -7,8 +7,10 @@
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnError="false"
stopOnFailure="false"
syntaxCheck="false"
syntaxCheck="true"
verbose="true"
>
<testsuites>
<testsuite name="Package Test Suite">

View File

@@ -1,13 +1,26 @@
# Laravel Socialite
<p align="center"><img src="https://laravel.com/assets/img/components/logo-socialite.svg"></p>
<p align="center">
<a href="https://travis-ci.org/laravel/socialite"><img src="https://travis-ci.org/laravel/socialite.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/socialite"><img src="https://poser.pugx.org/laravel/socialite/d/total.svg" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/socialite"><img src="https://poser.pugx.org/laravel/socialite/v/stable.svg" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/socialite"><img src="https://poser.pugx.org/laravel/socialite/license.svg" alt="License"></a>
</p>
## Introduction
Laravel Socialite provides an expressive, fluent interface to OAuth authentication with Facebook, Twitter, Google, LinkedIn, GitHub and Bitbucket. It handles almost all of the boilerplate social authentication code you are dreading writing.
**We are not accepting new adapters.**
**If you are using Laravel 5.3 or below, please use [Socialite 2.0](https://github.com/laravel/socialite/tree/2.0).**
Adapters for other platforms are listed at the community driven [Socialite Providers](https://socialiteproviders.github.io/) website.
## Official Documentation
Documentation for Socialite can be found on the [Laravel website](http://laravel.com/docs/authentication#social-authentication).
Documentation for Socialite can be found on the [Laravel website](http://laravel.com/docs/socialite).
### License
## License
Laravel Socialite is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)

View File

@@ -41,6 +41,13 @@ abstract class AbstractUser implements ArrayAccess, Contracts\User
*/
public $avatar;
/**
* The user's raw attributes.
*
* @var array
*/
public $user;
/**
* Get the unique identifier for the user.
*
@@ -91,6 +98,16 @@ abstract class AbstractUser implements ArrayAccess, Contracts\User
return $this->avatar;
}
/**
* Get the raw user array.
*
* @return array
*/
public function getRaw()
{
return $this->user;
}
/**
* Set the raw user array from the provider.
*
@@ -123,7 +140,7 @@ abstract class AbstractUser implements ArrayAccess, Contracts\User
* Determine if the given raw user attribute exists.
*
* @param string $offset
* @return bool
* @return bool
*/
public function offsetExists($offset)
{

View File

@@ -3,6 +3,7 @@
namespace Laravel\Socialite\Facades;
use Illuminate\Support\Facades\Facade;
use Laravel\Socialite\Contracts\Factory;
/**
* @see \Laravel\Socialite\SocialiteManager
@@ -16,6 +17,6 @@ class Socialite extends Facade
*/
protected static function getFacadeAccessor()
{
return 'Laravel\Socialite\Contracts\Factory';
return Factory::class;
}
}

View File

@@ -4,8 +4,9 @@ namespace Laravel\Socialite\One;
use Illuminate\Http\Request;
use InvalidArgumentException;
use Illuminate\Http\RedirectResponse;
use League\OAuth1\Client\Server\Server;
use Symfony\Component\HttpFoundation\RedirectResponse;
use League\OAuth1\Client\Credentials\TokenCredentials;
use Laravel\Socialite\Contracts\Provider as ProviderContract;
abstract class AbstractProvider implements ProviderContract
@@ -13,22 +14,22 @@ abstract class AbstractProvider implements ProviderContract
/**
* The HTTP request instance.
*
* @var Request
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* The OAuth server implementation.
*
* @var Server
* @var \League\OAuth1\Client\Server\Server
*/
protected $server;
/**
* Create a new provider instance.
*
* @param Request $request
* @param Server $server
* @param \Illuminate\Http\Request $request
* @param \League\OAuth1\Client\Server\Server $server
* @return void
*/
public function __construct(Request $request, Server $server)
@@ -40,11 +41,11 @@ abstract class AbstractProvider implements ProviderContract
/**
* Redirect the user to the authentication page for the provider.
*
* @return RedirectResponse
* @return \Illuminate\Http\RedirectResponse
*/
public function redirect()
{
$this->request->getSession()->put(
$this->request->session()->put(
'oauth.temp', $temp = $this->server->getTemporaryCredentials()
);
@@ -54,6 +55,7 @@ abstract class AbstractProvider implements ProviderContract
/**
* Get the User instance for the authenticated user.
*
* @throws \InvalidArgumentException
* @return \Laravel\Socialite\One\User
*/
public function user()
@@ -73,6 +75,31 @@ abstract class AbstractProvider implements ProviderContract
]);
}
/**
* Get a Social User instance from a known access token and secret.
*
* @param string $token
* @param string $secret
* @return \Laravel\Socialite\One\User
*/
public function userFromTokenAndSecret($token, $secret)
{
$tokenCredentials = new TokenCredentials();
$tokenCredentials->setIdentifier($token);
$tokenCredentials->setSecret($secret);
$user = $this->server->getUserDetails($tokenCredentials);
$instance = (new User)->setRaw($user->extra)
->setToken($tokenCredentials->getIdentifier(), $tokenCredentials->getSecret());
return $instance->map([
'id' => $user->uid, 'nickname' => $user->nickname,
'name' => $user->name, 'email' => $user->email, 'avatar' => $user->imageUrl,
]);
}
/**
* Get the token credentials for the request.
*
@@ -80,7 +107,7 @@ abstract class AbstractProvider implements ProviderContract
*/
protected function getToken()
{
$temp = $this->request->getSession()->get('oauth.temp');
$temp = $this->request->session()->get('oauth.temp');
return $this->server->getTokenCredentials(
$temp, $this->request->get('oauth_token'), $this->request->get('oauth_verifier')
@@ -100,7 +127,7 @@ abstract class AbstractProvider implements ProviderContract
/**
* Set the request instance.
*
* @param Request $request
* @param \Illuminate\Http\Request $request
* @return $this
*/
public function setRequest(Request $request)

View File

@@ -2,9 +2,16 @@
namespace Laravel\Socialite;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Illuminate\Support\Manager;
use Laravel\Socialite\Two\GithubProvider;
use Laravel\Socialite\Two\GoogleProvider;
use Laravel\Socialite\One\TwitterProvider;
use Laravel\Socialite\Two\FacebookProvider;
use Laravel\Socialite\Two\LinkedInProvider;
use Laravel\Socialite\Two\BitbucketProvider;
use League\OAuth1\Client\Server\Twitter as TwitterServer;
class SocialiteManager extends Manager implements Contracts\Factory
@@ -30,7 +37,7 @@ class SocialiteManager extends Manager implements Contracts\Factory
$config = $this->app['config']['services.github'];
return $this->buildProvider(
'Laravel\Socialite\Two\GithubProvider', $config
GithubProvider::class, $config
);
}
@@ -44,7 +51,7 @@ class SocialiteManager extends Manager implements Contracts\Factory
$config = $this->app['config']['services.facebook'];
return $this->buildProvider(
'Laravel\Socialite\Two\FacebookProvider', $config
FacebookProvider::class, $config
);
}
@@ -58,7 +65,7 @@ class SocialiteManager extends Manager implements Contracts\Factory
$config = $this->app['config']['services.google'];
return $this->buildProvider(
'Laravel\Socialite\Two\GoogleProvider', $config
GoogleProvider::class, $config
);
}
@@ -72,7 +79,7 @@ class SocialiteManager extends Manager implements Contracts\Factory
$config = $this->app['config']['services.linkedin'];
return $this->buildProvider(
'Laravel\Socialite\Two\LinkedInProvider', $config
LinkedInProvider::class, $config
);
}
@@ -86,7 +93,7 @@ class SocialiteManager extends Manager implements Contracts\Factory
$config = $this->app['config']['services.bitbucket'];
return $this->buildProvider(
'Laravel\Socialite\Two\BitbucketProvider', $config
BitbucketProvider::class, $config
);
}
@@ -101,7 +108,8 @@ class SocialiteManager extends Manager implements Contracts\Factory
{
return new $provider(
$this->app['request'], $config['client_id'],
$config['client_secret'], $config['redirect']
$config['client_secret'], $this->formatRedirectUrl($config),
Arr::get($config, 'guzzle', [])
);
}
@@ -130,10 +138,25 @@ class SocialiteManager extends Manager implements Contracts\Factory
return array_merge([
'identifier' => $config['client_id'],
'secret' => $config['client_secret'],
'callback_uri' => $config['redirect'],
'callback_uri' => $this->formatRedirectUrl($config),
], $config);
}
/**
* Format the callback URL, resolving a relative URI if needed.
*
* @param array $config
* @return string
*/
protected function formatRedirectUrl(array $config)
{
$redirect = value($config['redirect']);
return Str::startsWith($redirect, '/')
? $this->app['url']->to($redirect)
: $redirect;
}
/**
* Get the default driver name.
*

View File

@@ -3,6 +3,7 @@
namespace Laravel\Socialite;
use Illuminate\Support\ServiceProvider;
use Laravel\Socialite\Contracts\Factory;
class SocialiteServiceProvider extends ServiceProvider
{
@@ -20,7 +21,7 @@ class SocialiteServiceProvider extends ServiceProvider
*/
public function register()
{
$this->app->singleton('Laravel\Socialite\Contracts\Factory', function ($app) {
$this->app->singleton(Factory::class, function ($app) {
return new SocialiteManager($app);
});
}
@@ -32,6 +33,6 @@ class SocialiteServiceProvider extends ServiceProvider
*/
public function provides()
{
return ['Laravel\Socialite\Contracts\Factory'];
return [Factory::class];
}
}

View File

@@ -2,10 +2,12 @@
namespace Laravel\Socialite\Two;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use GuzzleHttp\ClientInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Illuminate\Http\RedirectResponse;
use Laravel\Socialite\Contracts\Provider as ProviderContract;
abstract class AbstractProvider implements ProviderContract
@@ -13,10 +15,17 @@ abstract class AbstractProvider implements ProviderContract
/**
* The HTTP request instance.
*
* @var Request
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* The HTTP Client instance.
*
* @var \GuzzleHttp\Client
*/
protected $httpClient;
/**
* The client ID.
*
@@ -73,17 +82,26 @@ abstract class AbstractProvider implements ProviderContract
*/
protected $stateless = false;
/**
* The custom Guzzle configuration options.
*
* @var array
*/
protected $guzzle = [];
/**
* Create a new provider instance.
*
* @param Request $request
* @param \Illuminate\Http\Request $request
* @param string $clientId
* @param string $clientSecret
* @param string $redirectUrl
* @param array $guzzle
* @return void
*/
public function __construct(Request $request, $clientId, $clientSecret, $redirectUrl)
public function __construct(Request $request, $clientId, $clientSecret, $redirectUrl, $guzzle = [])
{
$this->guzzle = $guzzle;
$this->request = $request;
$this->clientId = $clientId;
$this->redirectUrl = $redirectUrl;
@@ -117,7 +135,7 @@ abstract class AbstractProvider implements ProviderContract
* Map the raw user array to a Socialite User instance.
*
* @param array $user
* @return \Laravel\Socialite\User
* @return \Laravel\Socialite\Two\User
*/
abstract protected function mapUserToObject(array $user);
@@ -131,7 +149,7 @@ abstract class AbstractProvider implements ProviderContract
$state = null;
if ($this->usesState()) {
$this->request->getSession()->put('state', $state = Str::random(40));
$this->request->session()->put('state', $state = $this->getState());
}
return new RedirectResponse($this->getAuthUrl($state));
@@ -159,7 +177,7 @@ abstract class AbstractProvider implements ProviderContract
{
$fields = [
'client_id' => $this->clientId, 'redirect_uri' => $this->redirectUrl,
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
'scope' => $this->formatScopes($this->getScopes(), $this->scopeSeparator),
'response_type' => 'code',
];
@@ -191,10 +209,27 @@ abstract class AbstractProvider implements ProviderContract
throw new InvalidStateException;
}
$response = $this->getAccessTokenResponse($this->getCode());
$user = $this->mapUserToObject($this->getUserByToken(
$token = $this->getAccessToken($this->getCode())
$token = Arr::get($response, 'access_token')
));
return $user->setToken($token)
->setRefreshToken(Arr::get($response, 'refresh_token'))
->setExpiresIn(Arr::get($response, 'expires_in'));
}
/**
* Get a Social User instance from a known access token.
*
* @param string $token
* @return \Laravel\Socialite\Two\User
*/
public function userFromToken($token)
{
$user = $this->mapUserToObject($this->getUserByToken($token));
return $user->setToken($token);
}
@@ -209,18 +244,18 @@ abstract class AbstractProvider implements ProviderContract
return false;
}
$state = $this->request->getSession()->pull('state');
$state = $this->request->session()->pull('state');
return ! (strlen($state) > 0 && $this->request->input('state') === $state);
}
/**
* Get the access token for the given code.
* Get the access token response for the given code.
*
* @param string $code
* @return string
* @return array
*/
public function getAccessToken($code)
public function getAccessTokenResponse($code)
{
$postKey = (version_compare(ClientInterface::VERSION, '6') === 1) ? 'form_params' : 'body';
@@ -229,7 +264,7 @@ abstract class AbstractProvider implements ProviderContract
$postKey => $this->getTokenFields($code),
]);
return $this->parseAccessToken($response->getBody());
return json_decode($response->getBody(), true);
}
/**
@@ -246,17 +281,6 @@ abstract class AbstractProvider implements ProviderContract
];
}
/**
* Get the access token from the token response body.
*
* @param string $body
* @return string
*/
protected function parseAccessToken($body)
{
return json_decode($body, true)['access_token'];
}
/**
* Get the code from the request.
*
@@ -268,32 +292,85 @@ abstract class AbstractProvider implements ProviderContract
}
/**
* Set the scopes of the requested access.
* Merge the scopes of the requested access.
*
* @param array $scopes
* @param array|string $scopes
* @return $this
*/
public function scopes(array $scopes)
public function scopes($scopes)
{
$this->scopes = $scopes;
$this->scopes = array_unique(array_merge($this->scopes, (array) $scopes));
return $this;
}
/**
* Get a fresh instance of the Guzzle HTTP client.
* Set the scopes of the requested access.
*
* @param array|string $scopes
* @return $this
*/
public function setScopes($scopes)
{
$this->scopes = array_unique((array) $scopes);
return $this;
}
/**
* Get the current scopes.
*
* @return array
*/
public function getScopes()
{
return $this->scopes;
}
/**
* Set the redirect URL.
*
* @param string $url
* @return $this
*/
public function redirectUrl($url)
{
$this->redirectUrl = $url;
return $this;
}
/**
* Get a instance of the Guzzle HTTP client.
*
* @return \GuzzleHttp\Client
*/
protected function getHttpClient()
{
return new \GuzzleHttp\Client;
if (is_null($this->httpClient)) {
$this->httpClient = new Client($this->guzzle);
}
return $this->httpClient;
}
/**
* Set the Guzzle HTTP client instance.
*
* @param \GuzzleHttp\Client $client
* @return $this
*/
public function setHttpClient(Client $client)
{
$this->httpClient = $client;
return $this;
}
/**
* Set the request instance.
*
* @param Request $request
* @param \Illuminate\Http\Request $request
* @return $this
*/
public function setRequest(Request $request)
@@ -335,6 +412,16 @@ abstract class AbstractProvider implements ProviderContract
return $this;
}
/**
* Get the string used for session state.
*
* @return string
*/
protected function getState()
{
return Str::random(40);
}
/**
* Set the custom parameters of the request.
*

View File

@@ -14,6 +14,13 @@ class BitbucketProvider extends AbstractProvider implements ProviderInterface
*/
protected $scopes = ['email'];
/**
* The separating character for the requested scopes.
*
* @var string
*/
protected $scopeSeparator = ' ';
/**
* {@inheritdoc}
*/
@@ -101,7 +108,7 @@ class BitbucketProvider extends AbstractProvider implements ProviderInterface
$postKey => $this->getTokenFields($code),
]);
return $this->parseAccessToken($response->getBody());
return json_decode($response->getBody(), true)['access_token'];
}
/**
@@ -112,8 +119,6 @@ class BitbucketProvider extends AbstractProvider implements ProviderInterface
*/
protected function getTokenFields($code)
{
return [
'code' => $code, 'redirect_uri' => $this->redirectUrl, 'grant_type' => 'authorization_code',
];
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
}
}

View File

@@ -2,6 +2,9 @@
namespace Laravel\Socialite\Two;
use Illuminate\Support\Arr;
use GuzzleHttp\ClientInterface;
class FacebookProvider extends AbstractProvider implements ProviderInterface
{
/**
@@ -16,14 +19,14 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
*
* @var string
*/
protected $version = 'v2.5';
protected $version = 'v3.0';
/**
* The user fields being requested.
*
* @var array
*/
protected $fields = ['first_name', 'last_name', 'email', 'gender', 'verified'];
protected $fields = ['name', 'email', 'gender', 'verified', 'link'];
/**
* The scopes being requested.
@@ -39,6 +42,13 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
*/
protected $popup = false;
/**
* Re-request a declined permission.
*
* @var bool
*/
protected $reRequest = false;
/**
* {@inheritdoc}
*/
@@ -52,32 +62,25 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
*/
protected function getTokenUrl()
{
return $this->graphUrl.'/oauth/access_token';
}
/**
* Get the access token for the given code.
*
* @param string $code
* @return string
*/
public function getAccessToken($code)
{
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
'query' => $this->getTokenFields($code),
]);
return $this->parseAccessToken($response->getBody());
return $this->graphUrl.'/'.$this->version.'/oauth/access_token';
}
/**
* {@inheritdoc}
*/
protected function parseAccessToken($body)
public function getAccessTokenResponse($code)
{
parse_str($body);
$postKey = (version_compare(ClientInterface::VERSION, '6') === 1) ? 'form_params' : 'body';
return $access_token;
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
$postKey => $this->getTokenFields($code),
]);
$data = [];
$data = json_decode($response->getBody(), true);
return Arr::add($data, 'expires_in', Arr::pull($data, 'expires'));
}
/**
@@ -85,9 +88,15 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
*/
protected function getUserByToken($token)
{
$appSecretProof = hash_hmac('sha256', $token, $this->clientSecret);
$meUrl = $this->graphUrl.'/'.$this->version.'/me?access_token='.$token.'&fields='.implode(',', $this->fields);
$response = $this->getHttpClient()->get($this->graphUrl.'/'.$this->version.'/me?access_token='.$token.'&appsecret_proof='.$appSecretProof.'&fields='.implode(',', $this->fields), [
if (! empty($this->clientSecret)) {
$appSecretProof = hash_hmac('sha256', $token, $this->clientSecret);
$meUrl .= '&appsecret_proof='.$appSecretProof;
}
$response = $this->getHttpClient()->get($meUrl, [
'headers' => [
'Accept' => 'application/json',
],
@@ -103,14 +112,11 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
{
$avatarUrl = $this->graphUrl.'/'.$this->version.'/'.$user['id'].'/picture';
$firstName = isset($user['first_name']) ? $user['first_name'] : null;
$lastName = isset($user['last_name']) ? $user['last_name'] : null;
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => null, 'name' => $firstName.' '.$lastName,
'id' => $user['id'], 'nickname' => null, 'name' => isset($user['name']) ? $user['name'] : null,
'email' => isset($user['email']) ? $user['email'] : null, 'avatar' => $avatarUrl.'?type=normal',
'avatar_original' => $avatarUrl.'?width=1920',
'profileUrl' => isset($user['link']) ? $user['link'] : null,
]);
}
@@ -125,6 +131,10 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
$fields['display'] = 'popup';
}
if ($this->reRequest) {
$fields['auth_type'] = 'rerequest';
}
return $fields;
}
@@ -152,4 +162,16 @@ class FacebookProvider extends AbstractProvider implements ProviderInterface
return $this;
}
/**
* Re-request permissions which were previously declined.
*
* @return $this
*/
public function reRequest()
{
$this->reRequest = true;
return $this;
}
}

View File

@@ -3,6 +3,7 @@
namespace Laravel\Socialite\Two;
use Exception;
use Illuminate\Support\Arr;
class GithubProvider extends AbstractProvider implements ProviderInterface
{
@@ -80,8 +81,8 @@ class GithubProvider extends AbstractProvider implements ProviderInterface
protected function mapUserToObject(array $user)
{
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => $user['login'], 'name' => array_get($user, 'name'),
'email' => array_get($user, 'email'), 'avatar' => $user['avatar_url'],
'id' => $user['id'], 'nickname' => $user['login'], 'name' => Arr::get($user, 'name'),
'email' => Arr::get($user, 'email'), 'avatar' => $user['avatar_url'],
]);
}

View File

@@ -2,7 +2,7 @@
namespace Laravel\Socialite\Two;
use GuzzleHttp\ClientInterface;
use Illuminate\Support\Arr;
class GoogleProvider extends AbstractProvider implements ProviderInterface
{
@@ -19,6 +19,7 @@ class GoogleProvider extends AbstractProvider implements ProviderInterface
* @var array
*/
protected $scopes = [
'openid',
'profile',
'email',
];
@@ -39,23 +40,6 @@ class GoogleProvider extends AbstractProvider implements ProviderInterface
return 'https://accounts.google.com/o/oauth2/token';
}
/**
* Get the access token for the given code.
*
* @param string $code
* @return string
*/
public function getAccessToken($code)
{
$postKey = (version_compare(ClientInterface::VERSION, '6') === 1) ? 'form_params' : 'body';
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
$postKey => $this->getTokenFields($code),
]);
return $this->parseAccessToken($response->getBody());
}
/**
* Get the POST fields for the token request.
*
@@ -93,8 +77,9 @@ class GoogleProvider extends AbstractProvider implements ProviderInterface
protected function mapUserToObject(array $user)
{
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => array_get($user, 'nickname'), 'name' => $user['displayName'],
'email' => $user['emails'][0]['value'], 'avatar' => array_get($user, 'image')['url'],
'id' => $user['id'], 'nickname' => Arr::get($user, 'nickname'), 'name' => $user['displayName'],
'email' => $user['emails'][0]['value'], 'avatar' => Arr::get($user, 'image')['url'],
'avatar_original' => preg_replace('/\?sz=([0-9]+)/', '', Arr::get($user, 'image')['url']),
]);
}
}

View File

@@ -2,6 +2,9 @@
namespace Laravel\Socialite\Two;
class InvalidStateException extends \InvalidArgumentException
use InvalidArgumentException;
class InvalidStateException extends InvalidArgumentException
{
//
}

View File

@@ -2,6 +2,8 @@
namespace Laravel\Socialite\Two;
use Illuminate\Support\Arr;
class LinkedInProvider extends AbstractProvider implements ProviderInterface
{
/**
@@ -11,6 +13,13 @@ class LinkedInProvider extends AbstractProvider implements ProviderInterface
*/
protected $scopes = ['r_basicprofile', 'r_emailaddress'];
/**
* The separating character for the requested scopes.
*
* @var string
*/
protected $scopeSeparator = ' ';
/**
* The fields that are included in the profile.
*
@@ -27,7 +36,7 @@ class LinkedInProvider extends AbstractProvider implements ProviderInterface
*/
protected function getAuthUrl($state)
{
return $this->buildAuthUrlFromBase('https://www.linkedin.com/uas/oauth2/authorization', $state);
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state);
}
/**
@@ -35,7 +44,7 @@ class LinkedInProvider extends AbstractProvider implements ProviderInterface
*/
protected function getTokenUrl()
{
return 'https://www.linkedin.com/uas/oauth2/accessToken';
return 'https://www.linkedin.com/oauth/v2/accessToken';
}
/**
@@ -74,9 +83,9 @@ class LinkedInProvider extends AbstractProvider implements ProviderInterface
protected function mapUserToObject(array $user)
{
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => null, 'name' => array_get($user, 'formattedName'),
'email' => array_get($user, 'emailAddress'), 'avatar' => array_get($user, 'pictureUrl'),
'avatar_original' => array_get($user, 'pictureUrls.values.0'),
'id' => $user['id'], 'nickname' => null, 'name' => Arr::get($user, 'formattedName'),
'email' => Arr::get($user, 'emailAddress'), 'avatar' => Arr::get($user, 'pictureUrl'),
'avatar_original' => Arr::get($user, 'pictureUrls.values.0'),
]);
}

View File

@@ -13,6 +13,20 @@ class User extends AbstractUser
*/
public $token;
/**
* The refresh token that can be exchanged for a new access token.
*
* @var string
*/
public $refreshToken;
/**
* The number of seconds the access token is valid for.
*
* @var int
*/
public $expiresIn;
/**
* Set the token on the user.
*
@@ -25,4 +39,30 @@ class User extends AbstractUser
return $this;
}
/**
* Set the refresh token required to obtain a new access token.
*
* @param string $refreshToken
* @return $this
*/
public function setRefreshToken($refreshToken)
{
$this->refreshToken = $refreshToken;
return $this;
}
/**
* Set the number of seconds the access token is valid for.
*
* @param int $expiresIn
* @return $this
*/
public function setExpiresIn($expiresIn)
{
$this->expiresIn = $expiresIn;
return $this;
}
}

View File

@@ -1,70 +0,0 @@
<?php
use Mockery as m;
use Illuminate\Http\Request;
use Laravel\Socialite\One\AbstractProvider;
class OAuthOneTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testRedirectGeneratesTheProperSymfonyRedirectResponse()
{
$server = m::mock('League\OAuth1\Client\Server\Twitter');
$server->shouldReceive('getTemporaryCredentials')->once()->andReturn('temp');
$server->shouldReceive('getAuthorizationUrl')->once()->with('temp')->andReturn('http://auth.url');
$request = Request::create('foo');
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$session->shouldReceive('put')->once()->with('oauth.temp', 'temp');
$provider = new OAuthOneTestProviderStub($request, $server);
$response = $provider->redirect();
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
}
public function testUserReturnsAUserInstanceForTheAuthenticatedRequest()
{
$server = m::mock('League\OAuth1\Client\Server\Twitter');
$temp = m::mock('League\OAuth1\Client\Credentials\TemporaryCredentials');
$server->shouldReceive('getTokenCredentials')->once()->with($temp, 'oauth_token', 'oauth_verifier')->andReturn(
$token = m::mock('League\OAuth1\Client\Credentials\TokenCredentials')
);
$server->shouldReceive('getUserDetails')->once()->with($token)->andReturn($user = m::mock('League\OAuth1\Client\Server\User'));
$token->shouldReceive('getIdentifier')->once()->andReturn('identifier');
$token->shouldReceive('getSecret')->once()->andReturn('secret');
$user->uid = 'uid';
$user->email = 'foo@bar.com';
$user->extra = ['extra' => 'extra'];
$request = Request::create('foo', 'GET', ['oauth_token' => 'oauth_token', 'oauth_verifier' => 'oauth_verifier']);
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$session->shouldReceive('get')->once()->with('oauth.temp')->andReturn($temp);
$provider = new OAuthOneTestProviderStub($request, $server);
$user = $provider->user();
$this->assertInstanceOf('Laravel\Socialite\One\User', $user);
$this->assertEquals('uid', $user->id);
$this->assertEquals('foo@bar.com', $user->email);
}
/**
* @expectedException InvalidArgumentException
*/
public function testExceptionIsThrownWhenVerifierIsMissing()
{
$server = m::mock('League\OAuth1\Client\Server\Twitter');
$request = Request::create('foo');
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$provider = new OAuthOneTestProviderStub($request, $server);
$user = $provider->user();
}
}
class OAuthOneTestProviderStub extends AbstractProvider
{
}

View File

@@ -1,106 +0,0 @@
<?php
use Mockery as m;
use Illuminate\Http\Request;
use Laravel\Socialite\Two\User;
use Laravel\Socialite\Two\AbstractProvider;
class OAuthTwoTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testRedirectGeneratesTheProperSymfonyRedirectResponse()
{
$request = Request::create('foo');
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$session->shouldReceive('put')->once();
$provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect');
$response = $provider->redirect();
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
$this->assertEquals('http://auth.url', $response->getTargetUrl());
}
public function testUserReturnsAUserInstanceForTheAuthenticatedRequest()
{
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$session->shouldReceive('pull')->once()->with('state')->andReturn(str_repeat('A', 40));
$provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect_uri');
$provider->http = m::mock('StdClass');
$provider->http->shouldReceive('post')->once()->with('http://token.url', [
'headers' => ['Accept' => 'application/json'], 'form_params' => ['client_id' => 'client_id', 'client_secret' => 'client_secret', 'code' => 'code', 'redirect_uri' => 'redirect_uri'],
])->andReturn($response = m::mock('StdClass'));
$response->shouldReceive('getBody')->once()->andReturn('access_token=access_token');
$user = $provider->user();
$this->assertInstanceOf('Laravel\Socialite\Two\User', $user);
$this->assertEquals('foo', $user->id);
}
/**
* @expectedException Laravel\Socialite\Two\InvalidStateException
*/
public function testExceptionIsThrownIfStateIsInvalid()
{
$request = Request::create('foo', 'GET', ['state' => str_repeat('B', 40), 'code' => 'code']);
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$session->shouldReceive('pull')->once()->with('state')->andReturn(str_repeat('A', 40));
$provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect');
$user = $provider->user();
}
/**
* @expectedException Laravel\Socialite\Two\InvalidStateException
*/
public function testExceptionIsThrownIfStateIsNotSet()
{
$request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']);
$request->setLaravelSession($session = m::mock('Illuminate\Contracts\Session\Session'));
$session->shouldReceive('pull')->once()->with('state');
$provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect');
$user = $provider->user();
}
}
class OAuthTwoTestProviderStub extends AbstractProvider
{
public $http;
protected function getAuthUrl($state)
{
return 'http://auth.url';
}
protected function getTokenUrl()
{
return 'http://token.url';
}
protected function getUserByToken($token)
{
return ['id' => 'foo'];
}
protected function mapUserToObject(array $user)
{
return (new User)->map(['id' => $user['id']]);
}
/**
* Get a fresh instance of the Guzzle HTTP client.
*
* @return \GuzzleHttp\Client
*/
protected function getHttpClient()
{
if ($this->http) {
return $this->http;
}
return $this->http = m::mock('StdClass');
}
}