udpate facebook SDK to 5.6

This commit is contained in:
Toky Herizo
2018-02-12 11:24:14 +04:00
parent 30755e9c46
commit 6c853cf98c
5 changed files with 380 additions and 261 deletions

View File

@@ -67,7 +67,6 @@
"doctrine/migrations": "^1.0.0", "doctrine/migrations": "^1.0.0",
"doctrine/orm": "^2.4.0", "doctrine/orm": "^2.4.0",
"elasticsearch/elasticsearch": "~2.0", "elasticsearch/elasticsearch": "~2.0",
"facebook/php-sdk": "~3.2.3",
"firebase/php-jwt": "^3.0.0", "firebase/php-jwt": "^3.0.0",
"gedmo/doctrine-extensions": "~2.3.0", "gedmo/doctrine-extensions": "~2.3.0",
"goodby/csv": "^1.3.0", "goodby/csv": "^1.3.0",
@@ -119,7 +118,8 @@
"zend/gdata": "~1.12.1", "zend/gdata": "~1.12.1",
"alchemy/worker-bundle": "^0.1.6", "alchemy/worker-bundle": "^0.1.6",
"alchemy/queue-bundle": "^0.1.5", "alchemy/queue-bundle": "^0.1.5",
"google/recaptcha": "^1.1" "google/recaptcha": "^1.1",
"facebook/graph-sdk": "^5.6"
}, },
"require-dev": { "require-dev": {
"mikey179/vfsStream": "~1.5", "mikey179/vfsStream": "~1.5",

357
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -135,6 +135,7 @@ authentication:
options: options:
app-id: '' app-id: ''
secret: '' secret: ''
default-graph-version: 'v2.10'
twitter: twitter:
enabled: false enabled: false
options: options:

View File

@@ -21,13 +21,14 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface;
class Facebook extends AbstractProvider class Facebook extends AbstractProvider
{ {
/** @var \Facebook */ /** @var \Facebook\Facebook */
private $facebook; private $facebook;
public function __construct(\Facebook $facebook, UrlGenerator $generator) public function __construct(\Facebook\Facebook $facebook, UrlGenerator $generator, SessionInterface $session)
{ {
$this->facebook = $facebook; $this->facebook = $facebook;
$this->generator = $generator; $this->generator = $generator;
$this->session = $session;
} }
/** /**
@@ -51,14 +52,16 @@ class Facebook extends AbstractProvider
*/ */
public function authenticate() public function authenticate()
{ {
return new RedirectResponse($this->facebook->getLoginUrl([ return new RedirectResponse(
'scope' => 'email', $this->facebook->getRedirectLoginHelper()->getLoginUrl(
'redirect_uri' => $this->generator->generate( $this->generator->generate(
'login_authentication_provider_callback', 'login_authentication_provider_callback',
['providerId' => $this->getId()], ['providerId' => $this->getId()],
UrlGenerator::ABSOLUTE_URL UrlGenerator::ABSOLUTE_URL
),
['email']
) )
])); );
} }
/** /**
@@ -66,15 +69,15 @@ class Facebook extends AbstractProvider
*/ */
public function logout() public function logout()
{ {
$this->facebook->destroySession(); $this->session->remove('fb_access_token');
} }
/** /**
* @param \Facebook $facebook * @param \Facebook\Facebook $facebook
* *
* @return Facebook * @return Facebook
*/ */
public function setFacebook(\Facebook $facebook) public function setFacebook(\Facebook\Facebook $facebook)
{ {
$this->facebook = $facebook; $this->facebook = $facebook;
@@ -82,35 +85,55 @@ class Facebook extends AbstractProvider
} }
/** /**
* @return \Facebook * @return \Facebook\Facebook
*/ */
public function getFacebook() public function getFacebook()
{ {
return $this->facebook; return $this->facebook;
} }
/**
* @param $dataToRetrieve
* @return \Facebook\GraphNodes\GraphUser
*/
protected function getGraphUser($dataToRetrieve)
{
try {
$response = $this->facebook->get(
"/me?fields=" . implode(',', $dataToRetrieve),
$this->session->get('fb_access_token')
);
} catch(\Facebook\Exceptions\FacebookResponseException $e) {
throw new NotAuthenticatedException('Graph returned an error: ' . $e->getMessage());
exit;
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
throw new NotAuthenticatedException('Facebook SDK returned an error: ' . $e->getMessage());
exit;
}
if (!$response)
{
throw new NotAuthenticatedException('Not authenticated');
}
return $response->getGraphUser();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getIdentity() public function getIdentity()
{ {
try { $user = $this->getGraphUser(['id', 'name', 'email', 'picture', 'last_name', 'first_name']);
$data = $this->facebook->api('/me');
$identity = new Identity();
$identity->set(Identity::PROPERTY_ID, $data['id']); $identity = new Identity();
$identity->set(Identity::PROPERTY_IMAGEURL, sprintf(
'https://graph.facebook.com/%s/picture?return_ssl_resources=1',
$data['username']
));
$identity->set(Identity::PROPERTY_EMAIL, $data['email']);
$identity->set(Identity::PROPERTY_FIRSTNAME, $data['first_name']);
$identity->set(Identity::PROPERTY_LASTNAME, $data['last_name']);
$identity->set(Identity::PROPERTY_USERNAME, $data['username']);
} catch (\FacebookApiException $e) { $identity->set(Identity::PROPERTY_ID, $user['id']);
throw new NotAuthenticatedException('Unable to get profile informations', $e->getCode(), $e); $identity->set(Identity::PROPERTY_IMAGEURL, $user['picture']);
} $identity->set(Identity::PROPERTY_EMAIL, $user['email']);
$identity->set(Identity::PROPERTY_FIRSTNAME, $user['first_name']);
$identity->set(Identity::PROPERTY_LASTNAME, $user['last_name']);
$identity->set(Identity::PROPERTY_USERNAME, $user['first_name']);
return $identity; return $identity;
} }
@@ -120,9 +143,44 @@ class Facebook extends AbstractProvider
*/ */
public function onCallback(Request $request) public function onCallback(Request $request)
{ {
if (!$this->facebook->getUser()) { $helper = $this->facebook->getRedirectLoginHelper();
throw new NotAuthenticatedException('Facebook authentication failed');
try {
$accessToken = $helper->getAccessToken();
} catch(\Facebook\Exceptions\FacebookResponseException $e) {
throw new NotAuthenticatedException('Graph returned an error: ' . $e->getMessage());
exit;
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
throw new NotAuthenticatedException('Facebook SDK returned an error: ' . $e->getMessage());
exit;
} }
if (! isset($accessToken)) {
if ($helper->getError()) {
$error = "Error: " . $helper->getError() . "\n";
$error .= "Error Code: " . $helper->getErrorCode() . "\n";
$error .= "Error Reason: " . $helper->getErrorReason() . "\n";
$error .= "Error Description: " . $helper->getErrorDescription() . "\n";
throw new NotAuthenticatedException($error);
} else {
throw new NotAuthenticatedException('Facebook authentication failed');
}
exit;
}
$oAuth2Client = $this->facebook->getOAuth2Client();
if (! $accessToken->isLongLived()) {
try {
$accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
} catch (\Facebook\Exceptions\FacebookSDKException $e) {
throw new NotAuthenticatedException('Error getting long-lived access token: ' . $e->getMessage() );
exit;
}
}
$this->session->set('fb_access_token', (string) $accessToken);
} }
/** /**
@@ -130,11 +188,9 @@ class Facebook extends AbstractProvider
*/ */
public function getToken() public function getToken()
{ {
if (0 >= $this->facebook->getUser()) { $user = $this->getGraphUser(['id']);
throw new NotAuthenticatedException('Provider has not authenticated');
}
return new Token($this, $this->facebook->getUser()); return new Token($this, $user['id']);
} }
/** /**
@@ -194,11 +250,12 @@ class Facebook extends AbstractProvider
*/ */
public static function create(UrlGenerator $generator, SessionInterface $session, array $options) public static function create(UrlGenerator $generator, SessionInterface $session, array $options)
{ {
$config['appId'] = $options['app-id']; $config['app_id'] = $options['app-id'];
$config['secret'] = $options['secret']; $config['app_secret'] = $options['secret'];
$config['default_graph_version'] = $options['default-graph-version'];
$facebook = new \Facebook($config); $facebook = new \Facebook\Facebook($config);
return new static($facebook, $generator); return new static($facebook, $generator, $session);
} }
} }

View File

@@ -5,6 +5,7 @@ namespace Alchemy\Tests\Phrasea\Authentication\Provider;
use Alchemy\Phrasea\Authentication\Provider\Facebook; use Alchemy\Phrasea\Authentication\Provider\Facebook;
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface; use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
use Alchemy\Phrasea\Authentication\Provider\Token\Identity; use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
use Facebook\Authentication\AccessToken;
/** /**
* @group functional * @group functional
@@ -12,6 +13,8 @@ use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
*/ */
class FacebookTest extends ProviderTestCase class FacebookTest extends ProviderTestCase
{ {
const TOKEN = 'aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789';
public function testGetSetSession() public function testGetSetSession()
{ {
$this->markTestSkipped('testGetSetSession disabled for facebook'); $this->markTestSkipped('testGetSetSession disabled for facebook');
@@ -35,10 +38,6 @@ class FacebookTest extends ProviderTestCase
public function provideDataForFailingCallback() public function provideDataForFailingCallback()
{ {
$provider = $this->getProvider(); $provider = $this->getProvider();
$provider->getFacebook()->expects($this->any())
->method('getUser')
->will($this->returnValue(null));
return [ return [
[$provider, $this->getRequestMock()] [$provider, $this->getRequestMock()]
]; ];
@@ -52,10 +51,8 @@ class FacebookTest extends ProviderTestCase
public function provideDataForSuccessCallback() public function provideDataForSuccessCallback()
{ {
$provider = $this->getProvider(); $provider = $this->getProvider();
$provider->getFacebook()->expects($this->any()) $facebookMock = $this->getFacebookMock(true);
->method('getUser') $provider->setFacebook($facebookMock);
->will($this->returnValue('123456'));
return [ return [
[$provider, $this->getRequestMock()] [$provider, $this->getRequestMock()]
]; ];
@@ -63,14 +60,14 @@ class FacebookTest extends ProviderTestCase
protected function getProvider() protected function getProvider()
{ {
return new Facebook($this->getFacebookMock(), $this->getUrlGeneratorMock()); return new Facebook($this->getFacebookMock(), $this->getUrlGeneratorMock(), $this->getMockSession());
} }
protected function authenticateProvider(ProviderInterface $provider) protected function authenticateProvider(ProviderInterface $provider)
{ {
$provider->getFacebook()->expects($this->any()) $facebookMock = $this->getFacebookMock(true);
->method('getUser') $provider->setFacebook($facebookMock);
->will($this->returnValue('123456')); $provider->getSession()->set('fb_access_token', self::TOKEN);
} }
protected function getProviderForSuccessIdentity() protected function getProviderForSuccessIdentity()
@@ -78,27 +75,6 @@ class FacebookTest extends ProviderTestCase
$provider = $this->getProvider(); $provider = $this->getProvider();
$this->authenticateProvider($provider); $this->authenticateProvider($provider);
$facebook = $this->getMockBuilder('Facebook')
->disableOriginalConstructor()
->setMethods(['getLoginUrl', 'api', 'getUser'])
->getMock();
$facebook->expects($this->any())
->method('getLoginUrl')
->will($this->returnValue('http://www.facebook.com/'));
$facebook->expects($this->once())
->method('api')
->will($this->returnValue([
'id' => self::ID,
'username' => self::FIRSTNAME,
'first_name' => self::FIRSTNAME,
'last_name' => self::LASTNAME,
'email' => self::EMAIL,
]));
$provider->setFacebook($facebook);
return $provider; return $provider;
} }
@@ -123,6 +99,7 @@ class FacebookTest extends ProviderTestCase
return [ return [
'app-id' => 'zizi', 'app-id' => 'zizi',
'secret' => 's3cr3t', 'secret' => 's3cr3t',
'default-graph-version' => 'v2.10'
]; ];
} }
@@ -131,27 +108,100 @@ class FacebookTest extends ProviderTestCase
return $this->getProvider(); return $this->getProvider();
} }
private function getFacebookMock() private function getFacebookMock($ValidAccessToken = false)
{ {
$facebook = $this->getMockBuilder('Facebook') $facebook = $this->getMockBuilder('Facebook\Facebook')
->disableOriginalConstructor() ->disableOriginalConstructor()
->setMethods(['getLoginUrl', 'api', 'getUser']) ->setMethods(['getRedirectLoginHelper', 'get', 'getOAuth2Client'])
->getMock(); ->getMock();
$facebook->expects($this->any()) $helper = $this->getFacebookRedirectLoginHelperMock($ValidAccessToken);
->method('getLoginUrl')
->will($this->returnValue('http://www.facebook.com/'));
$facebook->expects($this->any()) $facebook->expects($this->any())
->method('api') ->method('getRedirectLoginHelper')
->will($this->returnCallback(function () use ($facebook) { ->will($this->returnValue($helper));
if (!$facebook->getUser()) {
throw new \FacebookApiException([ $OAuth2Client = $this->getOAuth2ClientMock();
'error_msg' => 'Not authenticated'
]); $facebook->expects($this->any())
} ->method('getOAuth2Client')
})); ->will($this->returnValue($OAuth2Client));
if ($ValidAccessToken)
{
$FacebookResponse = $this->getFacebookResponseMock();
$facebook->expects($this->any())
->method('get')
->will($this->returnValue($FacebookResponse));
}
return $facebook; return $facebook;
} }
private function getAccessTokenMock($valid = true)
{
$expiresAt = (time() + 3600);
return ($valid)? new AccessToken(self::TOKEN, $expiresAt) : null;
}
private function getFacebookRedirectLoginHelperMock($ValidAccessToken = true)
{
$accessToken = $this->getAccessTokenMock($ValidAccessToken);
$helper = $this->getMockBuilder('Facebook\Helpers\FacebookRedirectLoginHelper')
->disableOriginalConstructor()
->setMethods(['getLoginUrl', 'getAccessToken', 'getError'])
->getMock();
$helper->expects($this->any())
->method('getLoginUrl')
->will($this->returnValue('http://www.facebook.com/'));
$helper->expects($this->any())
->method('getAccessToken')
->will($this->returnValue($accessToken));
$helper->expects($this->any())
->method('getError')
->will($this->returnValue(null));
return $helper;
}
private function getOAuth2ClientMock()
{
$OAuth2Client = $this->getMockBuilder('Facebook\Authentication\OAuth2Client')
->disableOriginalConstructor()
->setMethods(['getLongLivedAccessToken'])
->getMock();
$OAuth2Client->expects($this->any())
->method('getLongLivedAccessToken')
->will($this->returnValue(self::TOKEN));
return $OAuth2Client;
}
private function getFacebookResponseMock()
{
$FacebookResponse = $this->getMockBuilder('Facebook\FacebookResponse')
->disableOriginalConstructor()
->setMethods(['getGraphUser'])
->getMock();
$FacebookResponse->expects($this->any())
->method('getGraphUser')
->will($this->returnValue([
'id' => self::ID,
'name' => self::FIRSTNAME,
'first_name' => self::FIRSTNAME,
'last_name' => self::LASTNAME,
'email' => self::EMAIL,
'picture' => self::IMAGEURL
]));
return $FacebookResponse;
}
} }