mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-18 15:33:15 +00:00
Add providers
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
abstract class AbstractProvider implements ProviderInterface
|
||||
{
|
||||
protected $generator;
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @param UrlGenerator $generator
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function setUrlGenerator(UrlGenerator $generator)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UrlGenerator
|
||||
*/
|
||||
public function getUrlGenerator()
|
||||
{
|
||||
return $this->generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SessionInterface $session
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function setSession(SessionInterface $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SessionInterface
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
protected function createState()
|
||||
{
|
||||
return md5(uniqid(microtime(true), true));
|
||||
}
|
||||
}
|
198
lib/Alchemy/Phrasea/Authentication/Provider/Facebook.php
Normal file
198
lib/Alchemy/Phrasea/Authentication/Provider/Facebook.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Token;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Alchemy\Phrasea\Authentication\Exception\NotAuthenticatedException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class Facebook extends AbstractProvider
|
||||
{
|
||||
/** @var \Facebook */
|
||||
private $facebook;
|
||||
|
||||
public function __construct(\Facebook $facebook, UrlGenerator $generator)
|
||||
{
|
||||
$this->facebook = $facebook;
|
||||
$this->generator = $generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'facebook';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Facebook';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
return new RedirectResponse($this->facebook->getLoginUrl(array(
|
||||
'scope' => 'email',
|
||||
'redirect_uri' => $this->generator->generate(
|
||||
'login_authentication_provider_callback',
|
||||
array('providerId' => $this->getId()),
|
||||
UrlGenerator::ABSOLUTE_URL
|
||||
)
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Facebook $facebook
|
||||
*
|
||||
* @return Facebook
|
||||
*/
|
||||
public function setFacebook(\Facebook $facebook)
|
||||
{
|
||||
$this->facebook = $facebook;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Facebook
|
||||
*/
|
||||
public function getFacebook()
|
||||
{
|
||||
return $this->facebook;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
try {
|
||||
$data = $this->facebook->api('/me');
|
||||
$identity = new Identity();
|
||||
|
||||
$identity->set(Identity::PROPERTY_ID, $data['id']);
|
||||
$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) {
|
||||
throw new RuntimeException('Unable to get profile informations', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onCallback(Request $request)
|
||||
{
|
||||
if (!$this->facebook->getUser()) {
|
||||
throw new NotAuthenticatedException('Facebook authentication failed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if (0 >= $this->facebook->getUser()) {
|
||||
throw new RuntimeException('Provider has not authenticated');
|
||||
}
|
||||
|
||||
return new Token($this, $this->facebook->getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIconURI()
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4w'
|
||||
. 'JK5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0W'
|
||||
. 'E1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iV'
|
||||
. 'zVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iY'
|
||||
. 'WRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExI'
|
||||
. 'DY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSR'
|
||||
. 'EYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1ze'
|
||||
. 'W50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6e'
|
||||
. 'G1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0U'
|
||||
. 'mVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZ'
|
||||
. 'WYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtc'
|
||||
. 'E1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMjgwMTE3NDA3MjA2ODExO'
|
||||
. 'EMxNEY3NEJCM0UzNjU4QyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFRjg3O'
|
||||
. 'UMwQTcxRUMxMUUyQjc5NzlGRUJDNjcwRkVDMyIgeG1wTU06SW5zdGFuY2VJRD0ie'
|
||||
. 'G1wLmlpZDpFRjg3OUMwOTcxRUMxMUUyQjc5NzlGRUJDNjcwRkVDMyIgeG1wOkNyZ'
|
||||
. 'WF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpIj4gPHhtc'
|
||||
. 'E1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExN'
|
||||
. 'zQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiIHN0UmVmOmRvY3VtZW50SUQ9Inhtc'
|
||||
. 'C5kaWQ6MDI4MDExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiLz4gPC9yZGY6R'
|
||||
. 'GVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlb'
|
||||
. 'mQ9InIiPz59EDiBAAAEEUlEQVR42txaXUgUURQ+szu76pZlYhoJJoYaEgUJRUUUQ'
|
||||
. 'hBBL0FPUdBjEUFPPfTaSw9B0GsR0UuPkQ8FQdFDVFBKJGaFS6b4r6Vru87fvZ0zM'
|
||||
. '2uz7o6Ozr02duXszs4MM+e733fuOfdeFc45rPcWg/+gqfShKIr95RoBi3uOo9YYG'
|
||||
. 'snHyh+r7gXb4TsvP7RX1Wy7r2tmm6GbEEWlMcvsS/e8v3jr0tku/KmjGV4QiQ3Vt'
|
||||
. 'Q8nx+dapoZ/QTYzD1GMF1TNrmR5wz087EDLoGVVT2wk9RxrmRj6CRND06DPG1EFA'
|
||||
. 'cnyRBMe1rmnzDwIioEyPWdAdjYHWlaHqI5aHP/IP2y1xIKXCVtODP228INFfNh1O'
|
||||
. '3gzWor89sopzizEyZht66BVUAiQ36o3ZyAGIP/XionaLSk4sq8B2pq2QnVVCjZWJ'
|
||||
. 'G256IYFmmbC5/Qk3H3cvVR6oM6PeUGAhShsOTG5IBJqDM6f2gMdB3ZCPKb43pdB7'
|
||||
. 'QfxpQAEsUB6kxnU8XgMrl04DLub65a9NxdwhCxiguJCJhOnO5oDAbD9CagKHzkxa'
|
||||
. 'TI6ebQ18P2mxQL5sggE2MhlMdHaWAOVqbKS1wZHZ+DT11HIooQWzo3MrI4JmXKqr'
|
||||
. '60seX5sag6u3nwKhrk6BRSCMEmHTJqc1Hjporj/xzRoWHCGKsX/apA7eUISE9znu'
|
||||
. 'QQgzDtLyEkeE35JFGuEUO8sBEG1E5dXO/k+loerEgpBGAgAg4vYENHKkyqoarxgi'
|
||||
. 'C2ZADFrp8oSxQwhO97RKhAILFmABghLUExcOXcQjh9qXva+Y/ubbFvcevvH4fKNz'
|
||||
. 'pWB4IKr2LCyzOH8hq802RkIgrKkJQhE2NDKaUYgXxblCbFDbNhCMpPVVpmxBSa7s'
|
||||
. 'J3x2y7FV8iEPbOzKCYsISDedA/AbEZb+N3SVAPtbfVF96UHp+Hdx8Gi8129Q4F8K'
|
||||
. 'SoARU6Knr/+Ylu+nTmxtySInm8jcPvBKzF5wmYBkYhiotT8wG8UC/POEjEhbz7h9'
|
||||
. '9yw71wUE86LuDQQSzHBBDIhswD0eS4XyoRJPeJfMstlQmApbqGmmKTAXjomBAU2d'
|
||||
. '3uE838QE1xgYNsgZMnJpwzhYuXkSEmanKw1kBNNiJxyXNbMbg2Y4BxZQJMWE34gm'
|
||||
. 'NCYYHJjYi2GWKpf7JmdJCb85QTimHBWOpi01Q7fjB1yhUWF4jHWMQmt89lb20Q3t'
|
||||
. 'WBwMnIDHJQdTqdEd9/OMrKT+EXrntTbLL8QRD+s0b4n1zHAhpRYcqGGipqZ83NTk'
|
||||
. '+kXj2gdAZzNeEshPSqKQuvtm8DZG25E245WA87uZDxKJICz7UtMDKN9RxtTPRdpM'
|
||||
. 'kw79OP5eTo4O5RqhECYLgMzrp/kr6Z65KS7J8FFSyzQFmuU/kkl72fW9ZVM/yPAA'
|
||||
. 'LuRXOCVA9oFAAAAAElFTkSuQmCC';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Facebook
|
||||
*/
|
||||
public static function create(UrlGenerator $generator, SessionInterface $session, array $options)
|
||||
{
|
||||
$config['appId'] = $options['app-id'];
|
||||
$config['secret'] = $options['secret'];
|
||||
|
||||
$facebook = new \Facebook($config);
|
||||
|
||||
return new static($facebook, $generator);
|
||||
}
|
||||
}
|
271
lib/Alchemy/Phrasea/Authentication/Provider/Github.php
Normal file
271
lib/Alchemy/Phrasea/Authentication/Provider/Github.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Token;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Alchemy\Phrasea\Authentication\Exception\NotAuthenticatedException;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Guzzle\Http\Client as Guzzle;
|
||||
use Guzzle\Http\ClientInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class Github extends AbstractProvider
|
||||
{
|
||||
private $client;
|
||||
|
||||
private $key;
|
||||
private $secret;
|
||||
|
||||
public function __construct(UrlGenerator $generator, SessionInterface $session, ClientInterface $client, $key, $secret)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
$this->session = $session;
|
||||
$this->client = $client;
|
||||
|
||||
$this->key = $key;
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client
|
||||
*
|
||||
* @return Github
|
||||
*/
|
||||
public function setGuzzleClient(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClientInterface
|
||||
*/
|
||||
public function getGuzzleClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'github';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Github';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$state = $this->createState();
|
||||
|
||||
$this->session->set('github.provider.state', $state);
|
||||
|
||||
return new RedirectResponse('https://github.com/login/oauth/authorize?' . http_build_query(array(
|
||||
'client_id' => $this->key,
|
||||
'scope' => 'user,user:email',
|
||||
'state' => $state,
|
||||
'redirect_uri' => $this->generator->generate(
|
||||
'login_authentication_provider_callback',
|
||||
array('providerId' => $this->getId()),
|
||||
UrlGenerator::ABSOLUTE_URL
|
||||
),
|
||||
), '', '&'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onCallback(Request $request)
|
||||
{
|
||||
if (!$this->session->has('github.provider.state')) {
|
||||
throw new RuntimeException('Invalid state value ; CSRF try ?');
|
||||
}
|
||||
|
||||
if ($request->query->get('state') !== $this->session->remove('github.provider.state')) {
|
||||
throw new RuntimeException('Invalid state value ; CSRF try ?');
|
||||
}
|
||||
|
||||
$guzzleRequest = $this->client->post('access_token');
|
||||
|
||||
$guzzleRequest->addPostFields(array(
|
||||
'code' => $request->query->get('code'),
|
||||
'redirect_uri' => $this->generator->generate(
|
||||
'login_authentication_provider_callback',
|
||||
array('providerId' => $this->getId()),
|
||||
UrlGenerator::ABSOLUTE_URL
|
||||
),
|
||||
'client_id' => $this->key,
|
||||
'client_secret' => $this->secret,
|
||||
));
|
||||
$guzzleRequest->setHeader('Accept', 'application/json');
|
||||
$response = $guzzleRequest->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while getting access_token');
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
|
||||
$this->session->remove('github.provider.state');
|
||||
$this->session->set('github.provider.access_token', $data['access_token']);
|
||||
|
||||
$request = $this->client->get('https://api.github.com/user');
|
||||
$request->getQuery()->add('access_token', $data['access_token']);
|
||||
$request->setHeader('Accept', 'application/json');
|
||||
|
||||
$response = $request->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while retrieving user info');
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
|
||||
$this->session->set('github.provider.id', $data['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if ('' === trim($this->session->get('github.provider.id'))) {
|
||||
throw new RuntimeException('Github has not authenticated');
|
||||
}
|
||||
|
||||
return new Token($this, $this->session->get('github.provider.id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
$identity = new Identity();
|
||||
|
||||
$request = $this->client->get('https://api.github.com/user');
|
||||
$request->getQuery()->add('access_token', $this->session->get('github.provider.access_token'));
|
||||
$request->setHeader('Accept', 'application/json');
|
||||
|
||||
$response = $request->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while retrieving user info');
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
|
||||
list($firstname, $lastname) = explode(' ', $data['name'], 2);
|
||||
|
||||
$identity->set(Identity::PROPERTY_EMAIL, $data['email']);
|
||||
$identity->set(Identity::PROPERTY_FIRSTNAME, $firstname);
|
||||
$identity->set(Identity::PROPERTY_ID, $data['id']);
|
||||
$identity->set(Identity::PROPERTY_IMAGEURL, $data['avatar_url']);
|
||||
$identity->set(Identity::PROPERTY_LASTNAME, $lastname);
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIconURI()
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4w'
|
||||
. 'JK5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MO'
|
||||
. 'mNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ'
|
||||
. '2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6b'
|
||||
. 'WV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgM'
|
||||
. 'jAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJod'
|
||||
. 'HRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZ'
|
||||
. 'XNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZ'
|
||||
. 'S5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL'
|
||||
. '3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZ'
|
||||
. 'G9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZ'
|
||||
. 'DowMjgwMTE3NDA3MjA2ODExOEMxNEY3NEJCM0UzNjU4QyIgeG1wTU06RG9jdW1lbnRJR'
|
||||
. 'D0ieG1wLmRpZDowMUNGRURDNTgzRUUxMUUyQjNFMDk5RUI0NTk2RTdBMiIgeG1wTU06S'
|
||||
. 'W5zdGFuY2VJRD0ieG1wLmlpZDowMUNGRURDNDgzRUUxMUUyQjNFMDk5RUI0NTk2RTdBM'
|
||||
. 'iIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpI'
|
||||
. 'j4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6ODUwR'
|
||||
. 'DRBRkIxQjIwNjgxMThDMTRGNzRCQjNFMzY1OEMiIHN0UmVmOmRvY3VtZW50SUQ9Inhtc'
|
||||
. 'C5kaWQ6MDI4MDExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiLz4gPC9yZGY6RGVzY'
|
||||
. '3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiP'
|
||||
. 'z4ThndjAAAG5ElEQVR42tRaaUxUVxT+GB+YIqjEiCwiVBoLGgSRRRHUxjSKVutSfzTGu'
|
||||
. 'CXUWnFNbGpKXYgLKribaGLin1ZjiwUxbq1xqaICKqKyKJtSwAUdBpBtYKbn3HlDGRiYY'
|
||||
. 'cRk5pLDzH3v3vPud89yzzlv7LRaLWy9SfzPzs5OfMikIOrT7rs1NU0HYglo7VgSdjoUi'
|
||||
. 'sKnT8NcXV1P0LURGo3G6nZc3dyc/evJkwvXrlv3nLrNRC0MRg+Cd9xBpVQ+blGrfZsaG'
|
||||
. '9DSQvetTdVor9+/f3/FP2D0EurVEjUwNkm+LUDQqgWAhvp6aFpbrVL/7SVpEn24yl1eZ'
|
||||
. 'IseBNtAX1YhlkCrlQIQTauVZBANMjXpQbBN2LP2MBBr9ljy2gYSveE1sxYp2qlTHxvyq'
|
||||
. 'o6sObJ3tZPa3VCwx2KkNnB2SPKmKzqCkL0urM8rGfFTnQ67/zHoUNjaKS51MhyZbBeEX'
|
||||
. 'pUskAR7tbuZmfjryhVkP8xBeUUFamtr4ezsDE8PDwQFjsaXU6YgPDSU3IniY0rCMsO+f'
|
||||
. 'uMfJO7fj6LiYtF3cHCA19ChGEbU2NSE4pIS5BcU4NTp3+E7fDjWr16NSROjPg4InRDMB'
|
||||
. '6FWq7Fj126cTk4Wuzt92jTMmzMbwUFBsLe3Nxh378EDnElJxcXLl7GCQMyfOxcbf9xgM'
|
||||
. 'M5iK5djJ/a7g6tevSpVvn2LxoZ6swCsWrceN9PT8ZmvL3bEx8Pv8xEm5+UXPMVPcXEoL'
|
||||
. 'CpCZEQEDiQl9hhIwNiQ7+kjl4gDwTcKo2atNU3bExIEgNCxY3H00EF86j3MrHmf+njj2'
|
||||
. 'OFDCAsJEfO37Uwwa54B9YY63bh5C3/8mQIfb2/s37Mbu5L24sKlS5gRPQ0/LF8u4q+ys'
|
||||
. 'n/R0NgIR8dPMNTTE5Ik4cjRYzh3/jxmz5qFfbt3YcGSpUhOScHkiRMxKSqy91wsTLhY9'
|
||||
. 'kJ7Dx4UidT2rVvQz8kJz8vK0NTcjDOpZ5GSdg7GchG2Gf315y9eiHnbaP6CRYuJ3wFET'
|
||||
. 'oiw2Gt1VicToswgN8peiN3lKH9/cc118GADkF2B17dBgwaJeaP8/ASf4pJS3M3ItFidF'
|
||||
. 'B3VSUP/uqO/r14VY+fN/lr0ldXVyMjK7NHO8UYoVSoxn/lwu3Ltqsln68kMSaDbXXiY8'
|
||||
. 'wgO5E2CAgNFPzUtDUpldY9AvKmqwlmax/PHEB/ml/PoUS8atonYqbKyEh50AlOGJcY9z'
|
||||
. 's2zSI9z8/LFfDZ45ldeUWlxzKYwlnR0R7V1dehPoYS+z+eFJa2Fskc9jwH9+6OO+Jp6d'
|
||||
. 'lees0PsJFI7aLupdDiTV6mhmEg/xtPD3SIQ7kOGtPFQ1dTAyalft881WxKsSqaMys3ND'
|
||||
. 'RUU3PEZwP3I8REWPThi3Dgxn/kwPw93j94x7DaRydIwRgGjRqKZVCg7J0f0g4MCEREe3'
|
||||
. 'iMAk6OixDyez3yYX8DIkd0+tz2ZdLFaE7vApyu3FPIurAbX6fSO3/QLncIzhZF2W26xl'
|
||||
. '/DNnDnYEvdzGz/mwy0qMtJiSXSyCa0Jm+AI1YfipKvXb+Db+fPx4GE2bt+5gw1r1yBm8'
|
||||
. 'WJk3r+P/YeP4J1S2TbHe9gwLFu0CCHBYzBwwADdo+gZhXRoXqMwnvnxvV6xiY7xkzHi5'
|
||||
. 'HZFTIw4gXfuScTShQtxLzub8okDyHn8hPz9YwMA3F5QWDKcAj/2Qno+bAtbt+8QNS7mZ'
|
||||
. '2eGZzTLO+kGaUzuSERYGGZGRyPtwgVs3LwZqyjo25mUhOTU1C5rRYVFxfAhiXBrJAAbN'
|
||||
. '28RkviKgkbmp/2A2q/UlXcy1dbErsTrqjeUkmahquotEuK3wsXFBXezspCQmGQ0dmK+B'
|
||||
. 'c+eYWdiIsVfJSIcXxsba9bzepBji+DJrF2RKOLctmkT9h06jHMXLyImdhUmRU6Ay0AXo'
|
||||
. '+Of5OXh5u10YQO86BlTpxKAlYKP9gMr8AaZXVlJSenLinLUkdfpSbt9NwNHjx8XIbmp5'
|
||||
. 'u3lhe+WLcP48DCLF/1F9HSDzK6TOllSKBgXForw0BDcJwO/cSsdufl5qHz5CvX19ZQUO'
|
||||
. 'cLdbQhG+vljIuUM7N04F+nN2lanko0pF9tdC6aIlMlERbjXi3OSsaTIpiuAbaVY2HIZs'
|
||||
. 'y12smVJ9LB4ZqUFZfnE1mpsWxLQ2sLria5BaBobG8rIh3tZM4pqleoddG9N9S/k26JY7'
|
||||
. 'rT+dvJUXJNaXSFR3M9hpdbK/pSq6nfHTpw4RWvlYnGzHow+7OCXeP2JhhD5cOrMNS7oX'
|
||||
. 'vBZywvJVnnxb4nKiUqJXhHVSO0GNEH3lv61fK3OSkGo5DXWymtuNfhZhLxoZ5kc5WvW8'
|
||||
. 'iMVjaxC9TKAWr1aGfxABbqX27zwvvL3PlYGgqWhliXQLH/X/CfAALHSg9r3u8gEAAAAA'
|
||||
. 'ElFTkSuQmCC';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(UrlGenerator $generator, SessionInterface $session, array $options)
|
||||
{
|
||||
if (!isset($options['client-id'])) {
|
||||
throw new InvalidArgumentException('Missing GitHub client-id parameter');
|
||||
}
|
||||
|
||||
if (!isset($options['client-secret'])) {
|
||||
throw new InvalidArgumentException('Missing GitHub client-secret parameter');
|
||||
}
|
||||
|
||||
return new Github($generator, $session, new Guzzle('https://github.com/login/oauth'), $options['client-id'], $options['client-secret']);
|
||||
}
|
||||
}
|
319
lib/Alchemy/Phrasea/Authentication/Provider/GooglePlus.php
Normal file
319
lib/Alchemy/Phrasea/Authentication/Provider/GooglePlus.php
Normal file
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Token;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Alchemy\Phrasea\Authentication\Exception\NotAuthenticatedException;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Guzzle\Http\Client as Guzzle;
|
||||
use Guzzle\Http\ClientInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class GooglePlus extends AbstractProvider
|
||||
{
|
||||
private $client;
|
||||
private $guzzle;
|
||||
private $plus;
|
||||
|
||||
public function __construct(UrlGenerator $generator, SessionInterface $session, \Google_Client $google, ClientInterface $guzzle)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
$this->session = $session;
|
||||
$this->client = $google;
|
||||
$this->guzzle = $guzzle;
|
||||
|
||||
$this->plus = new \Google_PlusService($this->client);
|
||||
|
||||
$this->client->setScopes(array(
|
||||
'https://www.googleapis.com/auth/plus.me',
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
));
|
||||
|
||||
$this->client->setRedirectUri(
|
||||
$this->generator->generate(
|
||||
'login_authentication_provider_callback', array(
|
||||
'providerId' => $this->getId(),
|
||||
), UrlGenerator::ABSOLUTE_URL
|
||||
)
|
||||
);
|
||||
|
||||
$this->client->setApprovalPrompt("auto");
|
||||
|
||||
if ($this->session->has('google-plus.provider.token')) {
|
||||
$this->client->setAccessToken($this->session->get('google-plus.provider.token'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client
|
||||
*
|
||||
* @return Github
|
||||
*/
|
||||
public function setGuzzleClient(ClientInterface $client)
|
||||
{
|
||||
$this->guzzle = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClientInterface
|
||||
*/
|
||||
public function getGuzzleClient()
|
||||
{
|
||||
return $this->guzzle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Google_Client $client
|
||||
*
|
||||
* @return GooglePlus
|
||||
*/
|
||||
public function setGoogleClient(\Google_Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Google_Client
|
||||
*/
|
||||
public function getGoogleClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Google_PlusService $plus
|
||||
*
|
||||
* @return GooglePlus
|
||||
*/
|
||||
public function setGooglePlusService(\Google_PlusService $plus)
|
||||
{
|
||||
$this->plus = $plus;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Google_PlusService
|
||||
*/
|
||||
public function getGooglePlusService()
|
||||
{
|
||||
return $this->plus;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'google-plus';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Google +';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$state = $this->createState();
|
||||
|
||||
$this->session->set('google-plus.provider.state', $state);
|
||||
$this->client->setState($state);
|
||||
|
||||
return new RedirectResponse($this->client->createAuthUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onCallback(Request $request)
|
||||
{
|
||||
if (!$this->session->has('google-plus.provider.state')) {
|
||||
throw new RuntimeException('Invalid state value ; CSRF try ?');
|
||||
}
|
||||
|
||||
if ($request->query->get('state') !== $this->session->remove('google-plus.provider.state')) {
|
||||
throw new RuntimeException('Invalid state value ; CSRF try ?');
|
||||
}
|
||||
|
||||
$this->client->authenticate($request->query->get('code'));
|
||||
|
||||
$token = json_decode($this->client->getAccessToken(), true);
|
||||
$ticket = $this->client->verifyIdToken($token['id_token']);
|
||||
|
||||
$this->session->set('google-plus.provider.token', json_encode($token));
|
||||
$this->session->set('google-plus.provider.id', $ticket->getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if (!ctype_digit($this->session->get('google-plus.provider.id'))) {
|
||||
throw new RuntimeException('Google + has not authenticated');
|
||||
}
|
||||
|
||||
return new Token($this, $this->session->get('google-plus.provider.id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
$identity = new Identity();
|
||||
|
||||
$token = json_decode($this->session->get('google-plus.provider.token'), true);
|
||||
$request = $this->guzzle->get(sprintf(
|
||||
'https://www.googleapis.com/oauth2/v1/tokeninfo?%s',
|
||||
http_build_query(array('access_token' => $token['access_token']), '', '&')
|
||||
));
|
||||
$response = $request->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while retrieving user info');
|
||||
}
|
||||
|
||||
try{
|
||||
$plusData = $this->plus->people->get('me');
|
||||
} catch (\Google_Exception $e) {
|
||||
throw new RuntimeException('Error while retrieving user info', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
|
||||
$identity->set(Identity::PROPERTY_EMAIL, $data['email']);
|
||||
|
||||
$identity->set(Identity::PROPERTY_FIRSTNAME, $plusData['name']['givenName']);
|
||||
$identity->set(Identity::PROPERTY_ID, $plusData['id']);
|
||||
$identity->set(Identity::PROPERTY_IMAGEURL, $plusData['image']['url']);
|
||||
$identity->set(Identity::PROPERTY_LASTNAME, $plusData['name']['familyName']);
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIconURI()
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4w'
|
||||
. 'JK5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MO'
|
||||
. 'mNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ'
|
||||
. '2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6b'
|
||||
. 'WV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgM'
|
||||
. 'jAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJod'
|
||||
. 'HRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZ'
|
||||
. 'XNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZ'
|
||||
. 'S5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL'
|
||||
. '3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZ'
|
||||
. 'G9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZ'
|
||||
. 'DowMjgwMTE3NDA3MjA2ODExOEMxNEY3NEJCM0UzNjU4QyIgeG1wTU06RG9jdW1lbnRJR'
|
||||
. 'D0ieG1wLmRpZDo2N0M5MkQ3OTcxRUUxMUUyQjc5NzlGRUJDNjcwRkVDMyIgeG1wTU06S'
|
||||
. 'W5zdGFuY2VJRD0ieG1wLmlpZDo2N0M5MkQ3ODcxRUUxMUUyQjc5NzlGRUJDNjcwRkVDM'
|
||||
. 'yIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpI'
|
||||
. 'j4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4M'
|
||||
. 'DExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiIHN0UmVmOmRvY3VtZW50SUQ9Inhtc'
|
||||
. 'C5kaWQ6MDI4MDExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiLz4gPC9yZGY6RGVzY'
|
||||
. '3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiP'
|
||||
. 'z6uF8PaAAAL1UlEQVR42txae4wdVRn/zdzXPu/d1227W5aWPizQFrolXZAFS3hUpICAC'
|
||||
. 'oLVNlU0NcVoiTEm/mEqGMVUVBqEolFEBUQbiokIAo1Q6COlrZTutrRLu9vd7pbtvu7uf'
|
||||
. 'c7j+J2ZM/eemZ177xITX5N8e86dM3PO9/ve58wqjDH8r18q/g+uIP+jKIrVCOLAAlL/v'
|
||||
. '+ligkwiQ7Q2CIfhvr6+9ubm5l+rqvqRk0MZzHvkPaA5RJAEvjxWC3nhzWMZbLq2AVtun'
|
||||
. 'O27cm73biSuvNJ61OHCkLgxpX6pe9TqOvBKG/A5+pkh0oh0hfsEaYJLPKzr+ruBQGA+X'
|
||||
. '/jp3YO4Z9txYG4Vve1hPN9XCvLpz+DAd5ag7fxqXyDDK1Ygt3+/1TeLkOHz2wua00eBh'
|
||||
. 'dSMEyWJsqrkG2EHAL8GEprdsWamV3kAyIuImDeVgpg4IHruyX3DRe0gfPPNtu597MNpF'
|
||||
. 'YkcJTPpGQcYXc1EMaIKbvoOCO4DEZcJGMyzimIDsfpMIjF7Uxg/PTSK4UndH0RHBxTPP'
|
||||
. 'UViVJGW8j7j048T1fJpuQJUaTwkvxwJ0pAhMeoiRawoWv5MBclhMIsDvZP+EWTBAktSx'
|
||||
. 'aTPPGNKEY8W96NCC5xnRTangPxSvCZUmN10TMrbd0ysAOaNbn8QTPInVWLSy7RXI8yjN'
|
||||
. 'WGSEQHAmipYLGe0NtBzXBucUc6A4kifSStJrPDfoQD29qZ9QSiG4csYfJiWmPXVkldRw'
|
||||
. 'WKOePF5FJXqyeRSNF2l4jFOaXlFmjekYChlWNaleOzBOHXKYkzxMQ+HaW+fTcPMSmbse'
|
||||
. 'E0Yay6mAPBBpqAFeUbmMSnB0UjOgGZMddHczp0uiSvCfsPCQ+tEuIlKHhsoYV7T0gS/1'
|
||||
. 'qyYgd++NGA7eF63ir9MFGY9F6EmGJg6l/6n7agRTDpXlmiU6GxdBNnKAGUtkikzEUgai'
|
||||
. 'CayaJAY5EY6JhLDhwLx8aX1WHppPQ53Ul5pqRKGKlSiSGCcTE6md15tCKrXlh77Heq6O'
|
||||
. 'q3s9GrHbHTOacTp+gqciVWgl+h4LIw0BUqdXlNJw1W6ifmJHFrGMoiPZzFrNI25p0dw0'
|
||||
. 'e5+tJgfEgS/fnBLK1bvOQc0UPwPBwvJzXFsp88Nc1zDJ5fE3BOcHMSrP1qD7fctx74FM'
|
||||
. '7B/NumjKmRrl5uiRlxlDSkHARM019nGSvKxeppXeEpaw8V3TGB53wTw8G6PEdhlRxV3A'
|
||||
. '+qf8gOy6dmTePhX3cAiMoaQ6o5MHATPmafTqG6pxMADS1FbYdtTwsjiU4/eiVf0E/TuU'
|
||||
. 'mCSqoCUBlVjNm8M7ujmm86Z7Xb8heqQLYA7nttAA51EPURDLk0kciai4am+/uO7LsBkU'
|
||||
. 'scTf+gljVDojYftFMMBpEhDAxmoTRV4ZePCPICzmQRu3b4B+3KHgRmXINifcE/qmIV3P'
|
||||
. '8PcAKzoQ43Knx+jtci09FLR6YatnTh5LuNrVtvWL8TW+y9C+zwq8IZyVPCRq51Joy6i4'
|
||||
. 't5PtODoQ5fiirl28bd36Dgu+81nsK9nFwKxxQiks+SvrECG0zfd9wx53PQ8S0SAmY/KX'
|
||||
. 'OaEL+w5VRnK4edrFmDtNc1F/eTt7gm8N5hGtCKIyxdG0RQtKPT1gSNY+dQdloQDDQvI9'
|
||||
. 'nWfbMWKx01W3ryMr79W3JwwrxLp99JYt+Vd/OL1Qdy6rBHXUoRqm1NDVVYh4lw2v9Yi7'
|
||||
. '9U91oeVz6yzTCVQTwWxrk0FUM58GMqaV+noxCNFjByH6qZd/xjBrt0UlRojmN9ajZnRM'
|
||||
. 'KojASR6Urhr9Wx8Y9VUTf3k4LMkly4EWjtormxp6X4o7bDimW4KCB72dPFkIxWJTSR9i'
|
||||
. 'iTdJyfRnaP7WQKZMbH5ywt9J+ubHCIvq6Q6SaN1zfIMytKd7jgrV3aYcmUqQPGtKSUwr'
|
||||
. 'hHe1rU1YNXimC+I2+ZdTfE8AT0zKUoSmoQXfoYp+qa7bxpSXyImxpjhuSfasiDy9ZBPb'
|
||||
. 'USA0mM5DDm7Ps+1dvFqbLjp+7Sv6IKRHBYllmmTKbVW35D60n1OhhgzzEIr+haQaWvCt'
|
||||
. 'V8QoMgnsqeS+GvXeNHI9eh19+OhOx+ltHsO5nCPvcQU6Rtu6bs0ZfhozITCyRozyoEwB'
|
||||
. 'cNe9TqaoX6Fggef7ytZqnyz/fN44YvPobKiAeaZLnpdEXMZPkybBbMrAk7J91mhGC2tC'
|
||||
. 'anU5k4+odvleD/Vjz1EGR3HXujFmm0nUOrs8Jb5V+HI117G4jntYKffscwh72cOOUzJD'
|
||||
. 'JqF+4ppk1crZQpAxk8IKLVnrSjE9821rTWYNyOG1sYwmusqMCteiUUNlQhWRnw3KPJ1Q'
|
||||
. 'W0c79z3F1zzxD144+CfgeZF9I7iCZnFQ6vriLVEdHKDOEqSDmloa2vEygvrcfmFdVh1S'
|
||||
. 'RwN1f/aOenr9/4eVzz+Wew99CIUAmJHnhKhtRjTjJUHse6uZtoIxXEdZWn3NQ7t9IvIj'
|
||||
. 'XVBT/XDTA+CZSn6ZMl5NR3h+ApEr3ycduz1RcHs+cozaHnwagz0H4PS1GqbBjy73FJ5o'
|
||||
. 'YQmSpbiyRNPItn9NLSh/dASw9bJlXVmELAPe1QhApYiBTbFUfexbQjPvq0okH2Dx3D5A'
|
||||
. 'yupnK4jwBF/AL7acJuVueVdV+3ku8c2Uu9jYEcHzuxYh0TnS9AmhxGoiiAQrUKglqimC'
|
||||
. 'kpVFViY2gj9bqyBNjaEoRduR/Lgt4qCaJ+1CDd13A2cOyOqAx42Tau1I5Xk9DrLPzPlX'
|
||||
. 'rmDAm3sEE4+tQxjXW8hGA0hGCMlhSrJjFUiZhHTbYITNanmUmuqoVBiH975EMZ2FtfG2'
|
||||
. 'ktWgz/IqLpVGCtkYeaTmS3fMadm7XIgep+/AZnhCYSbiHEWsBkXqYI5KcNJJwKUST8ML'
|
||||
. 'rFgFYL1YSTe3oGRl6/3BdHGHTsap/IkXZCyLktehFR5zPCMlQKR6NqKyd5zCBMjBkmXM'
|
||||
. '2eKlG84zFKri9YUcZ0Zjlb4xiVIZXgE4wdexcTb901ZcG6sGfXVFACyual1Uz4fMN+8k'
|
||||
. 'R8rBWKi5wmQ8Eniql17SfWXxaCoyeBolhVM2QLsEE0bqFUwtncrjMQx14KhQBBV3Kn5l'
|
||||
. 'wZTOpg2i7RyteDcKwVCT49YJ5x5E5KrBMEoj2b5AtMoVAt5wGKbiXAFcrStTh5/zLVgM'
|
||||
. 'pfG2GTCDnGmT/b2trIGipQdQXfpZFhhVKcHVee00rTPBJh0/Ep6sk8r7PwLptpnyvlwq'
|
||||
. 'YiTFi6YRK9rwSND7yM5SvuOQMjNEJvGZmk6myIlGIOWGYAaEeehrHC4p0qHf873FQVWj'
|
||||
. 'rFOIphaOMFRrWeYrSXTvfKbPQeprCGNNzXbkvVjshSAcpui6pabkEvZNYtj305flwtay'
|
||||
. 'Sf4KYTpmJgYswOKAoN8N1A907XgL3f90VpWtfg3i/uCWWKsFIjGZd9FOEYbnxG+vVQLF'
|
||||
. 'bJpM+vYP4RPyM7NgciOb6ZylCBJMIu+lJ9/+9G/48ibf6N9fKOwc8/HOkPaUZp+YwJIK'
|
||||
. 'RBqqBYLP70VGoXwNFWy3DMcodjRT4RZ4V+Oc+cjmXVGRC2pLfmBiWjbagrXl+Wr/PU/2'
|
||||
. '2DVKgo5jGtH52oN/90gK5xRlUt2rO7Cr2Lx+i3Wl51Ef5b2y1req/NadkKpZHa8b5A/5'
|
||||
. 'NJZJAc01C1ZhFnX78hPvOx7N2L8/RNQGhqFBLzfd6UtcdGx8powR0dHD/NOw5JNWL5pD'
|
||||
. '+KXtlGkUjAxqCF1TkNuQoOW1SgRGiRtg8aIcjr5kYYsmWBqIEfaUBDvWIUL1h6l2e0jz'
|
||||
. 'at+eDsO73oNSnwW1TWGzYju2RQVC7WGO7xS4h3xfC3OV7H8I17Dxo0b2zdv3vxIfX39e'
|
||||
. 'Q6y1NABDB/cionT+6CND0JPUlme0vNfg0IUKcOxKMK0Aao9fzma2r+NcEOb9e6u3oO4e'
|
||||
. '8t69HUeAWbOpNSgFiRZpEItta8gsxrBofFncCL5Ft05zk+JiEYcEGHx/YOHkjlEHEQjD'
|
||||
. '1jeD5L/wYtLP8W/6/NP/0R823CWV0tBaXed45UHr8/FPf4ZtGo63zD+zSD4UcsHgld+z'
|
||||
. 'GjIILJiAOLhIfGp9b/ln1QcQacEnxPit/lPAQYAZxcBzaHB/oIAAAAASUVORK5CYII=';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(UrlGenerator $generator, SessionInterface $session, array $options)
|
||||
{
|
||||
$client = new \Google_Client();
|
||||
|
||||
$client->setApplicationName('Phraseanet');
|
||||
$client->setClientId($options['client-id']);
|
||||
$client->setClientSecret($options['client-secret']);
|
||||
|
||||
return new GooglePlus($generator, $session, $client, new Guzzle());
|
||||
}
|
||||
}
|
259
lib/Alchemy/Phrasea/Authentication/Provider/Linkedin.php
Normal file
259
lib/Alchemy/Phrasea/Authentication/Provider/Linkedin.php
Normal file
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Token;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Alchemy\Phrasea\Authentication\Exception\NotAuthenticatedException;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Guzzle\Http\Client as Guzzle;
|
||||
use Guzzle\Http\ClientInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class Linkedin extends AbstractProvider
|
||||
{
|
||||
private $client;
|
||||
|
||||
private $key;
|
||||
private $secret;
|
||||
|
||||
public function __construct(UrlGenerator $generator, SessionInterface $session, ClientInterface $client, $key, $secret)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
$this->session = $session;
|
||||
$this->client = $client;
|
||||
|
||||
$this->key = $key;
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client
|
||||
*
|
||||
* @return Github
|
||||
*/
|
||||
public function setGuzzleClient(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClientInterface
|
||||
*/
|
||||
public function getGuzzleClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'linkedin';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'LinkedIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$state = $this->createState();
|
||||
|
||||
$this->session->set('linkedin.provider.state', $state);
|
||||
|
||||
return new RedirectResponse('https://www.linkedin.com/uas/oauth2/authorization?' . http_build_query(array(
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->key,
|
||||
'scope' => 'r_basicprofile r_emailaddress',
|
||||
'state' => $state,
|
||||
'redirect_uri' => $this->generator->generate(
|
||||
'login_authentication_provider_callback',
|
||||
array('providerId' => $this->getId()),
|
||||
UrlGenerator::ABSOLUTE_URL
|
||||
),
|
||||
), '', '&'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onCallback(Request $request)
|
||||
{
|
||||
if (!$this->session->has('linkedin.provider.state')) {
|
||||
throw new RuntimeException('Invalid state value ; CSRF try ?');
|
||||
}
|
||||
|
||||
if ($request->query->get('state') !== $this->session->remove('linkedin.provider.state')) {
|
||||
throw new RuntimeException('Invalid state value ; CSRF try ?');
|
||||
}
|
||||
|
||||
$guzzleRequest = $this->client->post('https://www.linkedin.com/uas/oauth2/accessToken?' . http_build_query(array(
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $request->query->get('code'),
|
||||
'redirect_uri' => $this->generator->generate(
|
||||
'login_authentication_provider_callback',
|
||||
array('providerId' => $this->getId()),
|
||||
UrlGenerator::ABSOLUTE_URL
|
||||
),
|
||||
'client_id' => $this->key,
|
||||
'client_secret' => $this->secret,
|
||||
), '', '&'));
|
||||
$response = $guzzleRequest->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while getting access_token');
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
$this->session->remove('linkedin.provider.state');
|
||||
$this->session->set('linkedin.provider.access_token', $data['access_token']);
|
||||
|
||||
$request = $this->client->get('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,positions,industry,picture-url,email-address)');
|
||||
$request->getQuery()
|
||||
->add('oauth2_access_token', $data['access_token'])
|
||||
->add('format', 'json');
|
||||
|
||||
$response = $request->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while retrieving user info');
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
|
||||
$this->session->set('linkedin.provider.id', $data['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if ('' === trim($this->session->get('linkedin.provider.id'))) {
|
||||
throw new RuntimeException('Linkedin has not authenticated');
|
||||
}
|
||||
|
||||
return new Token($this, $this->session->get('linkedin.provider.id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
$identity = new Identity();
|
||||
|
||||
$request = $this->client->get('https://api.linkedin.com/v1/people/~:(id,first-name,last-name,positions,industry,picture-url;secure=true,email-address)');
|
||||
$request->getQuery()
|
||||
->add('oauth2_access_token', $this->session->get('linkedin.provider.access_token'))
|
||||
->add('format', 'json');
|
||||
|
||||
$response = $request->send();
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new RuntimeException('Error while retrieving user info');
|
||||
}
|
||||
|
||||
$data = json_decode($response->getBody(true), true);
|
||||
|
||||
if (0 < $data['positions']['_total']) {
|
||||
$position = array_pop($data['positions']['values']);
|
||||
$identity->set(Identity::PROPERTY_COMPANY, $position['company']['name']);
|
||||
}
|
||||
|
||||
$identity->set(Identity::PROPERTY_EMAIL, $data['emailAddress']);
|
||||
$identity->set(Identity::PROPERTY_FIRSTNAME, $data['firstName']);
|
||||
$identity->set(Identity::PROPERTY_ID, $data['id']);
|
||||
$identity->set(Identity::PROPERTY_IMAGEURL, $data['pictureUrl']);
|
||||
$identity->set(Identity::PROPERTY_LASTNAME, $data['lastName']);
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIconURI()
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4w'
|
||||
. 'JK5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MO'
|
||||
. 'mNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ'
|
||||
. '2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6b'
|
||||
. 'WV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgM'
|
||||
. 'jAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJod'
|
||||
. 'HRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZ'
|
||||
. 'XNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZ'
|
||||
. 'S5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL'
|
||||
. '3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZ'
|
||||
. 'G9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZ'
|
||||
. 'DowMjgwMTE3NDA3MjA2ODExOEMxNEY3NEJCM0UzNjU4QyIgeG1wTU06RG9jdW1lbnRJR'
|
||||
. 'D0ieG1wLmRpZDo2N0M5MkQ3RDcxRUUxMUUyQjc5NzlGRUJDNjcwRkVDMyIgeG1wTU06S'
|
||||
. 'W5zdGFuY2VJRD0ieG1wLmlpZDo2N0M5MkQ3QzcxRUUxMUUyQjc5NzlGRUJDNjcwRkVDM'
|
||||
. 'yIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpI'
|
||||
. 'j4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4M'
|
||||
. 'DExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiIHN0UmVmOmRvY3VtZW50SUQ9Inhtc'
|
||||
. 'C5kaWQ6MDI4MDExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiLz4gPC9yZGY6RGVzY'
|
||||
. '3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiP'
|
||||
. 'z4zg+u0AAAD+0lEQVR42uxaSWgTURj+kkwWS7VirdZaS6Xa2tqCW3FBq4IHl0MPFT14c'
|
||||
. 'wE9K+hBD3oTRD1UPAgeBOsCgoinFulBQRGt2orSWqS2VatNapqmS5Z543uTyTKTTDIJI'
|
||||
. '32RPvjJvLxl3jffv7z/zVgkSUK+Fyv+gyJELyy0JACzKb8WRXgqTHVIoghJoPqHHiEk7'
|
||||
. 'kUgZAdTNd60TSIe/Bm7jj3bWmktQCVsidoEJYI9fSc+DUxieBTw+GizyJ/uML1w2MM4t'
|
||||
. 'LuGXtFFYjKRCQbChUAQcHuB32OUKE6NXrCxdZcqtbCgMXKHvHDGgMix1wrJGlLCWNAyw'
|
||||
. 'YiK2wHh3vUWUZnHeNGCiLhcGQj3IFzyQ9eAQBwAiQj/Mc6iihMqL8yAkPyJ5ELKWBIFk'
|
||||
. 'rcgokad/0wYswmHzYpj66pRt7gIXSNjuNPdTz2zxAMTkmGbaGtpQkttZaxeX7IQp9tfc'
|
||||
. '7CLJVF1ImnFSoE211Sohh5YVZ5xnGmSFoQoxW0ijRCR4O0Pt2po10+3obGmSEZ1IsZso'
|
||||
. 'uVeB87vWo/VxUV4/9ODS51dsxJfkkGEjXun714/Tj1+zqF3iqlT5id6ZN1qlBcVxurvq'
|
||||
. 'Hq1fxmSr8/uXK/qy/7vc4/j6KY12FtdgUXznBj2+fHk0wDufehHmBCTQYjEEIiTm9die'
|
||||
. '+WyWP3mq49o7/0mX1/c0winYItvdKg7bmmoQkNpccIMS3GwvgrHG2ux//ZTTAZDJnknE'
|
||||
. 'caNS9IPlDOahOrc7o0aAPHStLIMl/dtzdmwU3sno0C0KCRJ155clJWBMR9aX3SjrasvS'
|
||||
. 'X1ObK7DfLvdJO8kSil9sW7KnsqzpWj8MupF49X7GJ8JRNzx0AZcad6REP1t2FKxBB29g'
|
||||
. '2aok5RFwJFSg5BdtLrp1ssejE9Nx9rvvvmcdOuy+QU5BTsdw5ZyZAK64/yMgYS2Ee9EU'
|
||||
. 'p8Cu83YfTN6pxADIUYkWxQs0OmNI1LmOY30MQSCZJGepuqiN87InDmmxSkiNolITkyke'
|
||||
. 'ZLEwJyEmMSECFO8k81qSeO50jBhik2EszBsPe9ES6HTMYsgRGJSnMBsghANgzh84wFc9'
|
||||
. 'vgUvum4G606c03V1z0xlTSnkT65g4gCyVB+eMZ1276OeDKON9LnnzPB72lHFkzwDSLvm'
|
||||
. 'ZA3b1KenwDOqdOcOpmtTvnOROwlC9dMqBJ8ISmbCM4MAZYVXIOY8g0q+215z23VpEMiP'
|
||||
. 'jy7wHYUEBzqRIUXmfGPoqfzIYNCJQjNy3gn/Vkgn2gBlVSWU2EHRQWIvOPmobBDVvbal'
|
||||
. '226vlNhJ3W/BE06xM5TWAb/O5rfcwiCMeClMqqsNSho1CmoNEDpzAA4wM/XOKKyxilln'
|
||||
. 'eyziMBfAQYA4zp6M1LIbMYAAAAASUVORK5CYII=';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(UrlGenerator $generator, SessionInterface $session, array $options)
|
||||
{
|
||||
if (!isset($options['client-id'])) {
|
||||
throw new InvalidArgumentException('Missing LinkedIn client-id parameter');
|
||||
}
|
||||
|
||||
if (!isset($options['client-secret'])) {
|
||||
throw new InvalidArgumentException('Missing LinkedIn client-secret parameter');
|
||||
}
|
||||
|
||||
return new Linkedin($generator, $session, new Guzzle(), $options['client-id'], $options['client-secret']);
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Token;
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* Returns a unique identifier for the provider.
|
||||
*
|
||||
* Allowed characters are a-z and - (minus).
|
||||
* Examples : twitter => Twitter
|
||||
* google-plus => GooglePlus
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId();
|
||||
|
||||
/**
|
||||
* Returns an UTF-8 name for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Redirects to the actual authentication provider
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function authenticate();
|
||||
|
||||
|
||||
/**
|
||||
* This method is called on provider callback, whenever the auth was
|
||||
* successful or failure.
|
||||
*
|
||||
* @param Application $app
|
||||
* @param Request $request
|
||||
*/
|
||||
public function onCallback(Request $request);
|
||||
|
||||
/**
|
||||
* Returns the identity
|
||||
*
|
||||
* @return Identity
|
||||
*/
|
||||
public function getIdentity();
|
||||
|
||||
/**
|
||||
* Returns a Token
|
||||
*
|
||||
* @return Token
|
||||
*/
|
||||
public function getToken();
|
||||
|
||||
/**
|
||||
* Get an URI representing the provider
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIconURI();
|
||||
|
||||
/**
|
||||
* Creates a provider
|
||||
*
|
||||
* @param UrlGenerator $generator
|
||||
* @param SessionInterface $session
|
||||
* @param array $options
|
||||
*/
|
||||
public static function create(UrlGenerator $generator, SessionInterface $session, array $options);
|
||||
}
|
244
lib/Alchemy/Phrasea/Authentication/Provider/Twitter.php
Normal file
244
lib/Alchemy/Phrasea/Authentication/Provider/Twitter.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Token;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Alchemy\Phrasea\Authentication\Exception\NotAuthenticatedException;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class Twitter extends AbstractProvider
|
||||
{
|
||||
private $twitter;
|
||||
|
||||
public function __construct(UrlGenerator $generator, SessionInterface $session, \tmhOAuth $twitter)
|
||||
{
|
||||
$this->generator = $generator;
|
||||
$this->twitter = $twitter;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \tmhOAuth $twitter
|
||||
*
|
||||
* @return Twitter
|
||||
*/
|
||||
public function setTwitterClient(\tmhOAuth $twitter)
|
||||
{
|
||||
$this->twitter = $twitter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \tmhOAuth
|
||||
*/
|
||||
public function getTwitterClient()
|
||||
{
|
||||
return $this->twitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'twitter';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'Twitter';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$code = $this->twitter->request(
|
||||
'POST',
|
||||
$this->twitter->url('oauth/request_token', ''),
|
||||
array('oauth_callback' => $this->generator->generate(
|
||||
'login_authentication_provider_callback',
|
||||
array('providerId' => $this->getId()),
|
||||
UrlGenerator::ABSOLUTE_URL
|
||||
))
|
||||
);
|
||||
|
||||
if ($code != 200) {
|
||||
throw new RuntimeException('Unable to request twitter token');
|
||||
}
|
||||
|
||||
$oauth = $this->twitter->extract_params($this->twitter->response['response']);
|
||||
|
||||
$this->session->set('twitter.provider.oauth', $oauth);
|
||||
|
||||
return new RedirectResponse(sprintf(
|
||||
'%s?%s',
|
||||
$this->twitter->url("oauth/authenticate", ''),
|
||||
http_build_query(array('oauth_token' => $oauth['oauth_token']), '', '&')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onCallback(Request $request)
|
||||
{
|
||||
$oauth = $this->session->get('twitter.provider.oauth');
|
||||
|
||||
$this->twitter->config['user_token'] = $oauth['oauth_token'];
|
||||
$this->twitter->config['user_secret'] = $oauth['oauth_token_secret'];
|
||||
|
||||
$code = $this->twitter->request(
|
||||
'POST',
|
||||
$this->twitter->url('oauth/access_token', ''),
|
||||
array('oauth_verifier' => $request->query->get('oauth_verifier'))
|
||||
);
|
||||
|
||||
if ($code != 200) {
|
||||
throw new RuntimeException('Unable to get twitter access token');
|
||||
}
|
||||
|
||||
$access_token = $this->twitter->extract_params($this->twitter->response['response']);
|
||||
$this->session->set('twitter.provider.access_token', $access_token);
|
||||
$this->session->remove('twitter.provider.oauth');
|
||||
|
||||
$this->twitter->config['user_token'] = $access_token['oauth_token'];
|
||||
$this->twitter->config['user_secret'] = $access_token['oauth_token_secret'];
|
||||
|
||||
$code = $this->twitter->request(
|
||||
'GET', $this->twitter->url('1/account/verify_credentials')
|
||||
);
|
||||
|
||||
if ($code != 200) {
|
||||
throw new RuntimeException('Unable to get twitter credentials');
|
||||
}
|
||||
|
||||
$resp = json_decode($this->twitter->response['response'], true);
|
||||
|
||||
$this->session->set('twitter.provider.id', $resp['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if (0 >= $this->session->get('twitter.provider.id')) {
|
||||
throw new RuntimeException('Provider has not authenticated');
|
||||
}
|
||||
|
||||
return new Token($this, $this->session->get('twitter.provider.id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentity()
|
||||
{
|
||||
$access_token = $this->session->get('twitter.provider.access_token');
|
||||
|
||||
$this->twitter->config['user_token'] = $access_token['oauth_token'];
|
||||
$this->twitter->config['user_secret'] = $access_token['oauth_token_secret'];
|
||||
|
||||
$code = $this->twitter->request(
|
||||
'GET', $this->twitter->url('1/account/verify_credentials')
|
||||
);
|
||||
|
||||
if ($code != 200) {
|
||||
throw new RuntimeException('Unable to retrieve twitter identity');
|
||||
}
|
||||
|
||||
$resp = json_decode($this->twitter->response['response'], true);
|
||||
|
||||
$identity = new Identity();
|
||||
|
||||
$identity->set(Identity::PROPERTY_USERNAME, $resp['screen_name']);
|
||||
$identity->set(Identity::PROPERTY_IMAGEURL, $resp['profile_image_url_https']);
|
||||
$identity->set(Identity::PROPERTY_ID, $resp['id']);
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIconURI()
|
||||
{
|
||||
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4w'
|
||||
. 'JK5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MO'
|
||||
. 'mNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ'
|
||||
. '2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6b'
|
||||
. 'WV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgM'
|
||||
. 'jAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJod'
|
||||
. 'HRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZ'
|
||||
. 'XNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZ'
|
||||
. 'S5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL'
|
||||
. '3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZ'
|
||||
. 'G9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZ'
|
||||
. 'DowMjgwMTE3NDA3MjA2ODExOEMxNEY3NEJCM0UzNjU4QyIgeG1wTU06RG9jdW1lbnRJR'
|
||||
. 'D0ieG1wLmRpZDpFRjg3OUMwRTcxRUMxMUUyQjc5NzlGRUJDNjcwRkVDMyIgeG1wTU06S'
|
||||
. 'W5zdGFuY2VJRD0ieG1wLmlpZDpFRjg3OUMwRDcxRUMxMUUyQjc5NzlGRUJDNjcwRkVDM'
|
||||
. 'yIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChNYWNpbnRvc2gpI'
|
||||
. 'j4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4M'
|
||||
. 'DExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiIHN0UmVmOmRvY3VtZW50SUQ9Inhtc'
|
||||
. 'C5kaWQ6MDI4MDExNzQwNzIwNjgxMThDMTRGNzRCQjNFMzY1OEMiLz4gPC9yZGY6RGVzY'
|
||||
. '3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiP'
|
||||
. 'z67Nf6GAAAEqklEQVR42txaS2zcRBj+vXa8u26UV9NQQtsESFW1OVCVnuASDkXqpRISC'
|
||||
. 'HGgl9IeUNRDxRFx44B64UaLVFU8hYRUcUC9IFW8GsRDREWKFEAJJTyySTbpZr3rzfoxw'
|
||||
. 'z/j8darpM44D8nDSP/uOrY8/zf/983/z0w0Simo3nLwP2gG+9A0jX8JY8D02O8sNYLGq'
|
||||
. 'BPEflND3OQOvzY5c7JZ2PtBw4XDWRxx4nszpZ+/u3Dz/Jmf8NJF89if4yA6Cv0DH95b9'
|
||||
. 'keqdT+rzHm8MHLiGn6PodloDgNjxLRhUl0foeBDlqWeM/PD+PWQuGSj7UcgmAbyBL0Pk'
|
||||
. 'GmUZF7LAyIKzJptdGIg2IxLsj/rdqNZzGfme5xOeih5iiAyj6LI6C8YlDPidCM8ClSFS'
|
||||
. 'Bhi4HOtPHF/EqYQcEqplcXbQARCD4FilUgbCD8CQkD1SDBNEIVBCCBK04kIUVOisLA9B'
|
||||
. 'OCh/74kBl2Tj9qTvSY8N2TBwT0GVD0C35TW4MZfDu/roGVAB75rdos12zo6MVHLBuL0Y'
|
||||
. 'BH68zq8N1tLfO6FQxZcHO3mZUHUnujLwzMPF8HHzgYRxNlvl7acn9pnJ8ryBJrk2473m'
|
||||
. 'XD6gAWFHIUrv9c2dOJAUYfxo11tAKI2itFhkfx8rgZn8D3vbzIYknQSQCRBGMKzlw93w'
|
||||
. 'TEc2cu/rMJszWt7Zmx/AfSclkjJYz15eGe6LN1v4vKUxOgkY3dW3Puc35uHj8YG4M0Tv'
|
||||
. 'fDUPhOd0/gzvfnkxWETQ3Hu9hKUm0S6Xwk6ERwRuTxx488avPhYJxdrNKqnHrG4udjbH'
|
||||
. '1UPrI5kEBUUue0GO5vsfLGmkGmXRnvhru21QMSbiRQ60mNu+o7ltUC6P0lhCzpJvvTfu'
|
||||
. 'gfPP9qzLQemK+62y5y2WHutjE2l7OOZGiytbY8KtzFfyPYXWbKwWd2EKKikVRoBnL21A'
|
||||
. 'FMxgadpLOnd+tuR7i+y5LKDz0w4S6SIb2XNh3nHh6EuAzqNdNtU13+tQn2bot5YE0Fos'
|
||||
. 'm2pHqA4SWoA/2CJcX1qNVVfUiAoCaNAU04Xb0wswkrTh1eOdkNHQmJraQ+n3/GvF8Bu7'
|
||||
. 'Mz+VtvwUfHBK9kU5iHoyz+U4dnP5mC26iV2yKI9/tUi3Ck1UvcT2aalOHmAeNblAcxsO'
|
||||
. 'czKnVh+jmC2PjXUCS9h+VE0HhyJElLo1S9LMDnf2MVFEQnrJiJBJ8PQ4dzxPrgw2sOBJ'
|
||||
. 'LU6Dv+7UxW4NrkMdjOAnW7rMjZbEMlEwsYZ6e2JBbjyYxmeHt4DJ/dbWASasM/S+f0yT'
|
||||
. 'r/TOPV+P+/AxFwdGrvg/MbCxumVizvFlo3j+vDFb6vcMrM8ZSmCBgovTymvm6jaIAKxS'
|
||||
. 'UBV3rLhZ0eqR4JTiWtC4X0nEQq16cQ3z9Q4KUrKE1RQSmVNRAlPYToR6jTmUBeHIMMYS'
|
||||
. 'H1lGcJTCCKsVYqzi6D66dXXSb06v9USebctsMv3nJtvfYK+sjLYjXZeNXZT07Q8XnRBe'
|
||||
. 'D48jDaI1g/hCaWekSAwh9mRb5lttKDdRVtgS3Uj9kATwlP6xaiChvCU0sgICF9EYFX4a'
|
||||
. 'AufAyNGJ1fcAIGYRcGE7PyTSuSjI/y0xTX5T4ABAP5AumSxg/sSAAAAAElFTkSuQmCC';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(UrlGenerator $generator, SessionInterface $session, array $options)
|
||||
{
|
||||
$twitter = new \tmhOAuth(array(
|
||||
'consumer_key' => $options['consumer-key'],
|
||||
'consumer_secret' => $options['consumer-secret'],
|
||||
));
|
||||
|
||||
return new Twitter($generator, $session, $twitter);
|
||||
}
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Authentication\Provider\Facebook;
|
||||
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
|
||||
class FacebookTest extends ProviderTestCase
|
||||
{
|
||||
public function testGetSetSession()
|
||||
{
|
||||
$this->markTestSkipped('testGetSetSession disabled for facebook');
|
||||
}
|
||||
|
||||
public function testGetSetGuzzleClient()
|
||||
{
|
||||
$this->markTestSkipped('testGetSetGuzzleClient disabled for facebook');
|
||||
}
|
||||
|
||||
public function testIsBuiltWithFactory()
|
||||
{
|
||||
$this->markTestSkipped('Skipping because \Facebook runs session_start');
|
||||
}
|
||||
|
||||
public function testCreate()
|
||||
{
|
||||
$this->markTestSkipped('Skipping because \Facebook runs session_start');
|
||||
}
|
||||
|
||||
public function provideDataForFailingCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$provider->getFacebook()->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue(null));
|
||||
|
||||
return array(
|
||||
array($provider, $this->getRequestMock())
|
||||
);
|
||||
}
|
||||
|
||||
public function provideDataForSuccessCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$provider->getFacebook()->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue('123456'));
|
||||
|
||||
return array(
|
||||
array($provider, $this->getRequestMock())
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProvider()
|
||||
{
|
||||
return new Facebook($this->getFacebookMock(), $this->getUrlGeneratorMock());
|
||||
}
|
||||
|
||||
protected function authenticate(ProviderInterface $provider)
|
||||
{
|
||||
$provider->getFacebook()->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue('123456'));
|
||||
}
|
||||
|
||||
protected function getProviderForSuccessIdentity()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->authenticate($provider);
|
||||
|
||||
$facebook = $this->getMockBuilder('Facebook')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('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(array(
|
||||
'id' => self::ID,
|
||||
'username' => self::FIRSTNAME,
|
||||
'first_name' => self::FIRSTNAME,
|
||||
'last_name' => self::LASTNAME,
|
||||
'email' => self::EMAIL,
|
||||
)));
|
||||
|
||||
$provider->setFacebook($facebook);
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getProviderForFailingIdentity()
|
||||
{
|
||||
return $this->getProvider();
|
||||
}
|
||||
|
||||
protected function getAvailableFieldsForIdentity()
|
||||
{
|
||||
return array(
|
||||
Identity::PROPERTY_ID => self::ID,
|
||||
Identity::PROPERTY_USERNAME => self::FIRSTNAME,
|
||||
Identity::PROPERTY_FIRSTNAME => self::FIRSTNAME,
|
||||
Identity::PROPERTY_LASTNAME => self::LASTNAME,
|
||||
Identity::PROPERTY_EMAIL => self::EMAIL,
|
||||
);
|
||||
}
|
||||
|
||||
protected function getTestOptions()
|
||||
{
|
||||
return array(
|
||||
'app-id' => 'zizi',
|
||||
'secret' => 's3cr3t',
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForAuthentication()
|
||||
{
|
||||
return $this->getProvider();
|
||||
}
|
||||
|
||||
private function getFacebookMock()
|
||||
{
|
||||
$facebook = $this->getMockBuilder('Facebook')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('getLoginUrl', 'api', 'getUser'))
|
||||
->getMock();
|
||||
|
||||
$facebook->expects($this->any())
|
||||
->method('getLoginUrl')
|
||||
->will($this->returnValue('http://www.facebook.com/'));
|
||||
|
||||
$facebook->expects($this->any())
|
||||
->method('api')
|
||||
->will($this->returnCallback(function () use ($facebook) {
|
||||
if (!$facebook->getUser()) {
|
||||
throw new \FacebookApiException('Not authenticated');
|
||||
}
|
||||
}));
|
||||
|
||||
return $facebook;
|
||||
}
|
||||
}
|
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Authentication\Provider\Github;
|
||||
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
|
||||
class GithubTest extends ProviderTestCase
|
||||
{
|
||||
public function provideDataForFailingCallback()
|
||||
{
|
||||
$state = md5(mt_rand());
|
||||
|
||||
$provider = $this->provideFailingProvider();
|
||||
$provider->getSession()->set('github.provider.state', $state . mt_rand());
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array('state' => $state));
|
||||
|
||||
return array(
|
||||
array($this->getProvider(), $this->getRequestMock()),
|
||||
array($provider, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function provideDataForSuccessCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
$requestPost = $this->getMock('Guzzle\Http\Message\EntityEnclosingRequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$requestPost->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('post')
|
||||
->will($this->returnValue($requestPost));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
|
||||
$state = md5(mt_rand());
|
||||
$provider->getSession()->set('github.provider.state', $state);
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array('state' => $state));
|
||||
|
||||
return array(
|
||||
array($provider, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTestOptions()
|
||||
{
|
||||
return array(
|
||||
'client-id' => 'github-client-id',
|
||||
'client-secret' => 'github-client-secret',
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForAuthentication()
|
||||
{
|
||||
return $this->getProvider();
|
||||
}
|
||||
|
||||
protected function getProviderForSuccessIdentity()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getBody')
|
||||
->with($this->equalTo(true))
|
||||
->will($this->returnValue(json_encode(array(
|
||||
'id' => self::ID,
|
||||
'name' => self::FIRSTNAME . ' ' . self::LASTNAME,
|
||||
'email' => self::EMAIL,
|
||||
'avatar_url' => self::IMAGEURL,
|
||||
))));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
$provider->getSession()->set('github.provider.id', 'github-id');
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getProviderForFailingIdentity()
|
||||
{
|
||||
return $this->provideFailingProvider();
|
||||
}
|
||||
|
||||
protected function provideFailingProvider()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(401));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getAvailableFieldsForIdentity()
|
||||
{
|
||||
return array(
|
||||
Identity::PROPERTY_ID => self::ID,
|
||||
Identity::PROPERTY_FIRSTNAME => self::FIRSTNAME,
|
||||
Identity::PROPERTY_LASTNAME => self::LASTNAME,
|
||||
Identity::PROPERTY_EMAIL => self::EMAIL,
|
||||
Identity::PROPERTY_IMAGEURL => self::IMAGEURL,
|
||||
);
|
||||
}
|
||||
|
||||
protected function authenticate(ProviderInterface $provider)
|
||||
{
|
||||
$provider->getSession()->set('github.provider.id', 'github-id');
|
||||
}
|
||||
|
||||
protected function getProvider()
|
||||
{
|
||||
return new Github($this->getUrlGeneratorMock(), $this->getMockSession(), $this->getGuzzleMock(), 'key', 'secret');
|
||||
}
|
||||
}
|
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Authentication\Provider\GooglePlus;
|
||||
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
|
||||
class GooglePlusTest extends ProviderTestCase
|
||||
{
|
||||
public function testGetSetGoogleClient()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->assertInstanceOf('Google_client', $provider->getGoogleClient());
|
||||
$google = $this->getMockBuilder('Google_Client')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$provider->setGoogleClient($google);
|
||||
$this->assertEquals($google, $provider->getGoogleClient());
|
||||
}
|
||||
|
||||
public function provideDataForFailingCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$state = md5(mt_rand());
|
||||
$provider->getSession()->set('google-plus.provider.state', $state . mt_rand());
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array('state' => $state));
|
||||
|
||||
return array(
|
||||
array($this->provideFailingProvider(), $this->getRequestMock()),
|
||||
array($provider, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function provideDataForSuccessCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
$requestPost = $this->getMock('Guzzle\Http\Message\EntityEnclosingRequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$requestPost->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('post')
|
||||
->will($this->returnValue($requestPost));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
|
||||
$state = md5(mt_rand());
|
||||
$provider->getSession()->set('google-plus.provider.state', $state);
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array(
|
||||
'state' => $state,
|
||||
));
|
||||
|
||||
$ticket = $this->getMockBuilder('Google_LoginTicket')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$provider->getGoogleClient()->expects($this->once())
|
||||
->method('verifyIdToken')
|
||||
->will($this->returnValue($ticket));
|
||||
|
||||
return array(
|
||||
array($provider, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTestOptions()
|
||||
{
|
||||
return array(
|
||||
'client-id' => 'google-plus-client-id',
|
||||
'client-secret' => 'google-plus-client-secret',
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForSuccessIdentity()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getBody')
|
||||
->with($this->equalTo(true))
|
||||
->will($this->returnValue(json_encode(array(
|
||||
'email' => self::EMAIL
|
||||
))));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
$provider->getSession()->set('google-plus.provider.id', '12345678');
|
||||
|
||||
$people = $this->getMockBuilder('Google_PeopleServiceResource')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$people->expects($this->once())
|
||||
->method('get')
|
||||
->will($this->returnValue(array(
|
||||
'name' => array(
|
||||
'givenName' => self::FIRSTNAME,
|
||||
'familyName' => self::LASTNAME,
|
||||
),
|
||||
'id' => self::ID,
|
||||
'image' => array(
|
||||
'url' => self::IMAGEURL
|
||||
)
|
||||
)));
|
||||
|
||||
$provider->getGooglePlusService()->people = $people;
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getAvailableFieldsForIdentity()
|
||||
{
|
||||
return array(
|
||||
Identity::PROPERTY_ID => self::ID,
|
||||
Identity::PROPERTY_FIRSTNAME => self::FIRSTNAME,
|
||||
Identity::PROPERTY_LASTNAME => self::LASTNAME,
|
||||
Identity::PROPERTY_EMAIL => self::EMAIL,
|
||||
Identity::PROPERTY_IMAGEURL => self::IMAGEURL,
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForFailingIdentity()
|
||||
{
|
||||
return $this->provideFailingProvider();
|
||||
}
|
||||
|
||||
protected function provideFailingProvider()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(401));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function authenticate(ProviderInterface $provider)
|
||||
{
|
||||
$provider->getSession()->set('google-plus.provider.id', '12345678');
|
||||
}
|
||||
|
||||
protected function getProvider()
|
||||
{
|
||||
$googleMock = $this->getMockBuilder('Google_Client')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$googleMock->expects($this->any())
|
||||
->method('createAuthUrl')
|
||||
->will($this->returnValue('https://www.google.com/auth'));
|
||||
|
||||
$plus = $this->getMockBuilder('Google_PlusService')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
|
||||
$google = new GooglePlus($this->getUrlGeneratorMock(), $this->getMockSession(), $googleMock, $this->getGuzzleMock());
|
||||
$google->setGooglePlusService($plus);
|
||||
|
||||
return $google;
|
||||
}
|
||||
|
||||
protected function getProviderForAuthentication()
|
||||
{
|
||||
return $this->getProvider();
|
||||
}
|
||||
}
|
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Authentication\Provider\Linkedin;
|
||||
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
|
||||
class LinkedinTest extends ProviderTestCase
|
||||
{
|
||||
public function provideDataForFailingCallback()
|
||||
{
|
||||
$state = md5(mt_rand());
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array('state' => $state));
|
||||
|
||||
$provider1 = $this->getProvider();
|
||||
$provider1->setGuzzleClient($this->getGuzzleMock(401));
|
||||
$provider1->getSession()->set('linkedin.provider.state', $state);
|
||||
|
||||
$mock = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
$requestPost = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$queryString->expects($this->any())
|
||||
->method('add')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->at(0))
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$response->expects($this->at(1))
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(401));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$requestPost->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('post')
|
||||
->will($this->returnValue($requestPost));
|
||||
|
||||
|
||||
$provider2 = $this->getProvider();
|
||||
$provider2->setGuzzleClient($mock);
|
||||
$provider2->getSession()->set('linkedin.provider.state', $state);
|
||||
|
||||
|
||||
return array(
|
||||
array($this->getProvider(), $this->getRequestMock()),
|
||||
array($provider1, $request),
|
||||
array($provider2, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function provideDataForSuccessCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
$requestPost = $this->getMock('Guzzle\Http\Message\EntityEnclosingRequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$queryString->expects($this->any())
|
||||
->method('add')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$requestPost->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('post')
|
||||
->will($this->returnValue($requestPost));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
|
||||
$state = md5(mt_rand());
|
||||
$provider->getSession()->set('linkedin.provider.state', $state);
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array('state' => $state));
|
||||
|
||||
return array(
|
||||
array($provider, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTestOptions()
|
||||
{
|
||||
return array(
|
||||
'client-id' => 'linkedin-client-id',
|
||||
'client-secret' => 'linkedin-client-secret',
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForSuccessIdentity()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$queryString->expects($this->any())
|
||||
->method('add')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(200));
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getBody')
|
||||
->with($this->equalTo(true))
|
||||
->will($this->returnValue(json_encode(array(
|
||||
'positions' => array(
|
||||
'_total' => 1,
|
||||
'values' => array(
|
||||
array(
|
||||
'company' => array(
|
||||
'name' => self::COMPANY
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
'emailAddress' => self::EMAIL,
|
||||
'firstName' => self::FIRSTNAME,
|
||||
'id' => self::ID,
|
||||
'pictureUrl' => self::IMAGEURL,
|
||||
'lastName' => self::LASTNAME,
|
||||
))));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
$provider->getSession()->set('linkedin.provider.id', 'linkedin-id');
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getAvailableFieldsForIdentity()
|
||||
{
|
||||
return array(
|
||||
Identity::PROPERTY_ID => self::ID,
|
||||
Identity::PROPERTY_FIRSTNAME => self::FIRSTNAME,
|
||||
Identity::PROPERTY_LASTNAME => self::LASTNAME,
|
||||
Identity::PROPERTY_EMAIL => self::EMAIL,
|
||||
Identity::PROPERTY_IMAGEURL => self::IMAGEURL,
|
||||
Identity::PROPERTY_COMPANY => self::COMPANY,
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForFailingIdentity()
|
||||
{
|
||||
return $this->provideFailingProvider();
|
||||
}
|
||||
|
||||
protected function provideFailingProvider()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$guzzle = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$queryString->expects($this->any())
|
||||
->method('add')
|
||||
->will($this->returnSelf());
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue(401));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$guzzle->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getProviderForAuthentication()
|
||||
{
|
||||
return $this->getProvider();
|
||||
}
|
||||
|
||||
protected function authenticate(ProviderInterface $provider)
|
||||
{
|
||||
$provider->getSession()->set('linkedin.provider.id', 'linkedin-id');
|
||||
}
|
||||
|
||||
protected function getProvider()
|
||||
{
|
||||
return new Linkedin($this->getUrlGeneratorMock(), $this->getMockSession(), $this->getGuzzleMock(), 'key', 'secret');
|
||||
}
|
||||
}
|
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
|
||||
use DataURI\Parser;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Factory as ProviderFactory;
|
||||
use Guzzle\Http\Message\RequestInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
|
||||
abstract class ProviderTestCase extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $session;
|
||||
|
||||
const COMPANY = 'Company test';
|
||||
const EMAIL = 'email@test.com';
|
||||
const FIRSTNAME = 'first-name';
|
||||
const USERNAME = 'user-name';
|
||||
const LASTNAME = 'last-name';
|
||||
const ID = '1234567890';
|
||||
const IMAGEURL = 'https://www.home.org/image.png';
|
||||
|
||||
public function testGetId()
|
||||
{
|
||||
$this->assertInternalType('string', $this->getProvider()->getId());
|
||||
}
|
||||
|
||||
public function testGetSetUrlGenerator()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->assertInstanceOf('Symfony\Component\Routing\Generator\UrlGenerator', $provider->getUrlGenerator());
|
||||
$generator = $this->getUrlGeneratorMock();
|
||||
|
||||
$provider->setUrlGenerator($generator);
|
||||
$this->assertEquals($generator, $provider->getUrlGenerator());
|
||||
}
|
||||
|
||||
public function testGetSetSession()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\SessionInterface', $provider->getSession());
|
||||
$session = $this->getMockSession();
|
||||
|
||||
$provider->setSession($session);
|
||||
$this->assertEquals($session, $provider->getSession());
|
||||
}
|
||||
|
||||
public function testGetSetGuzzleClient()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->assertInstanceOf('Guzzle\Http\CLientInterface', $provider->getGuzzleClient());
|
||||
$guzzle = $this->getGuzzleMock();
|
||||
|
||||
$provider->setGuzzleClient($guzzle);
|
||||
$this->assertEquals($guzzle, $provider->getGuzzleClient());
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertInternalType('string', $this->getProvider()->getName());
|
||||
}
|
||||
|
||||
public function testIsBuiltWithFactory()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$built = $this->getProviderFactory()->build($provider->getId(), $this->getTestOptions());
|
||||
|
||||
$this->assertInstanceOf(get_class($provider), $built);
|
||||
}
|
||||
|
||||
public function testAuthenticate()
|
||||
{
|
||||
$provider = $this->getProviderForAuthentication();
|
||||
$redirect = $provider->authenticate();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $redirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDataForSuccessCallback
|
||||
*/
|
||||
public function testOnCallbackWithSuccess(ProviderInterface $provider, $request)
|
||||
{
|
||||
$provider->onCallback($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDataForFailingCallback
|
||||
* @expectedException Alchemy\Phrasea\Exception\RuntimeException
|
||||
*/
|
||||
public function testOnCallbackWithFailure($provider, $request)
|
||||
{
|
||||
$provider->onCallback($request);
|
||||
}
|
||||
|
||||
public function testGetToken()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->authenticate($provider);
|
||||
|
||||
$token = $provider->getToken();
|
||||
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Authentication\Provider\Token\Token', $token);
|
||||
$this->assertEquals($provider, $token->getProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Alchemy\Phrasea\Exception\RuntimeException
|
||||
*/
|
||||
public function testGetTokenWhenNotAuthenticated()
|
||||
{
|
||||
$this->getProvider()->getToken();
|
||||
}
|
||||
|
||||
public function testGetIdentity()
|
||||
{
|
||||
$provider = $this->getProviderForSuccessIdentity();
|
||||
$identity = $provider->getIdentity();
|
||||
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Authentication\Provider\Token\Identity', $identity);
|
||||
|
||||
foreach ($this->getAvailableFieldsForIdentity() as $name=>$value) {
|
||||
$this->assertEquals($value, $identity->get($name), "testing $name");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Alchemy\Phrasea\Exception\RuntimeException
|
||||
*/
|
||||
public function testGetIdentityWhenNotAuthenticated()
|
||||
{
|
||||
$provider = $this->getProviderForFailingIdentity();
|
||||
$provider->getIdentity();
|
||||
}
|
||||
|
||||
public function testGetIconURI()
|
||||
{
|
||||
Parser::parse($this->getProvider()->getIconURI());
|
||||
}
|
||||
|
||||
public function testCreate()
|
||||
{
|
||||
$name = get_class($this->getProvider());
|
||||
$provider = $name::create($this->getUrlGeneratorMock(), $this->getMockSession(), $this->getTestOptions());
|
||||
|
||||
$this->assertInstanceOf($name, $provider);
|
||||
}
|
||||
|
||||
abstract public function provideDataForFailingCallback();
|
||||
|
||||
abstract public function provideDataForSuccessCallback();
|
||||
|
||||
protected function addQueryParameter(Request $request, array $parameters)
|
||||
{
|
||||
$query = $this->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$query->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnCallback(function ($param) use ($parameters) {
|
||||
if (isset($parameters[$param])) {
|
||||
return $parameters[$param];
|
||||
}
|
||||
}));
|
||||
|
||||
$request->query = $query;
|
||||
}
|
||||
|
||||
protected function getMockSession()
|
||||
{
|
||||
return new Session(new MockFileSessionStorage());
|
||||
}
|
||||
|
||||
abstract protected function authenticate(ProviderInterface $provider);
|
||||
|
||||
abstract protected function getProviderForAuthentication();
|
||||
|
||||
abstract protected function getProviderForSuccessIdentity();
|
||||
|
||||
abstract protected function getProviderForFailingIdentity();
|
||||
|
||||
abstract protected function getAvailableFieldsForIdentity();
|
||||
|
||||
/**
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
abstract protected function getProvider();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getTestOptions();
|
||||
|
||||
protected function getUrlGeneratorMock()
|
||||
{
|
||||
return $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
protected function getRequestMock()
|
||||
{
|
||||
return $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
protected function getGuzzleMock($statusCode = 200)
|
||||
{
|
||||
$mock = $this->getMock('Guzzle\Http\ClientInterface');
|
||||
|
||||
$requestGet = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
$requestPost = $this->getMock('Guzzle\Http\Message\RequestInterface');
|
||||
|
||||
$queryString = $this->getMockBuilder('Guzzle\Http\QueryString')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($queryString));
|
||||
|
||||
$response = $this->getMockBuilder('Guzzle\Http\Message\Response')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$response->expects($this->any())
|
||||
->method('getStatusCode')
|
||||
->will($this->returnValue($statusCode));
|
||||
|
||||
$requestGet->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$requestPost->expects($this->any())
|
||||
->method('send')
|
||||
->will($this->returnValue($response));
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue($requestGet));
|
||||
|
||||
$mock->expects($this->any())
|
||||
->method('post')
|
||||
->will($this->returnValue($requestPost));
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProviderFactory
|
||||
*/
|
||||
private function getProviderFactory()
|
||||
{
|
||||
return new ProviderFactory($this->getUrlGeneratorMock(), $this->getMockSession());
|
||||
}
|
||||
}
|
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Authentication\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Authentication\Provider\Twitter;
|
||||
use Alchemy\Phrasea\Authentication\Provider\ProviderInterface;
|
||||
use Alchemy\Phrasea\Authentication\Provider\Token\Identity;
|
||||
|
||||
class TwitterTest extends ProviderTestCase
|
||||
{
|
||||
public function testGetSetGuzzleClient()
|
||||
{
|
||||
$this->markTestSkipped('testGetSetGuzzleClient disabled for facebook');
|
||||
}
|
||||
|
||||
public function testGetSetTwitterClient()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$this->assertInstanceOf('tmhOAuth', $provider->getTwitterClient());
|
||||
$client = $this->getMockBuilder('tmhOAuth')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$provider->setTwitterClient($client);
|
||||
$this->assertEquals($client, $provider->getTwitterClient());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Alchemy\Phrasea\Exception\RuntimeException
|
||||
*/
|
||||
public function testAuthenticateWithFailure()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$provider->getTwitterClient()->expects($this->once())
|
||||
->method('request')
|
||||
->will($this->returnValue(401));
|
||||
|
||||
$provider->authenticate();
|
||||
}
|
||||
|
||||
public function getProviderForAuthentication()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$provider->getTwitterClient()->expects($this->once())
|
||||
->method('request')
|
||||
->will($this->returncallback(function () use ($provider) {
|
||||
$provider->getTwitterClient()->response = array(
|
||||
'response' => array(
|
||||
'oauth_token' => 'twitter-oauth-token',
|
||||
)
|
||||
);
|
||||
|
||||
return 200;
|
||||
}));
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
public function provideDataForFailingCallback()
|
||||
{
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array());
|
||||
|
||||
$provider1 = $this->getProvider();
|
||||
$provider1->getTwitterClient()->expects($this->once())
|
||||
->method('request')
|
||||
->will($this->returnValue(401));
|
||||
|
||||
$first = true;
|
||||
$provider2 = $this->getProvider();
|
||||
$provider2->getTwitterClient()->expects($this->exactly(2))
|
||||
->method('request')
|
||||
->will($this->returnCallback(function () use (&$first, $provider2) {
|
||||
if (!$first) {
|
||||
return 401;
|
||||
} else {
|
||||
|
||||
$provider2->getTwitterClient()->response = array(
|
||||
'response' => array(
|
||||
'oauth_token' => 'twitter-oauth-token',
|
||||
)
|
||||
);
|
||||
|
||||
$first = false;
|
||||
return 200;
|
||||
}
|
||||
}));
|
||||
|
||||
return array(
|
||||
array($provider1, $request),
|
||||
array($provider2, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function provideDataForSuccessCallback()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
$state = md5(mt_rand());
|
||||
$provider->getSession()->set('twitter.provider.state', $state);
|
||||
|
||||
$request = $this->getRequestMock();
|
||||
$this->addQueryParameter($request, array('state' => $state));
|
||||
|
||||
$provider->getTwitterClient()->expects($this->any())
|
||||
->method('request')
|
||||
->will($this->returnCallback(function ($method) use ($provider) {
|
||||
switch($method) {
|
||||
case 'POST':
|
||||
$provider->getTwitterClient()->response = array(
|
||||
'response' => array(
|
||||
'oauth_token' => 'twitter-oauth-token',
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'GET':
|
||||
$provider->getTwitterClient()->response = array(
|
||||
'response' => json_encode(array(
|
||||
'id' => self::ID,
|
||||
))
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Invalid method %s', $method));
|
||||
break;
|
||||
}
|
||||
|
||||
return 200;
|
||||
}));
|
||||
|
||||
$provider->getTwitterClient()->expects($this->once())
|
||||
->method('extract_params')
|
||||
->will($this->returnValue(array(
|
||||
'oauth_token_secret' => 'token secret',
|
||||
'oauth_token' => 'token',
|
||||
)));
|
||||
|
||||
return array(
|
||||
array($provider, $request),
|
||||
);
|
||||
}
|
||||
|
||||
public function getTestOptions()
|
||||
{
|
||||
return array(
|
||||
'consumer-key' => 'twitter-consumer-key',
|
||||
'consumer-secret' => 'twitter-consumer-secret',
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForSuccessIdentity()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
$provider->getSession()->set('twitter.provider.access_token', array(
|
||||
'oauth_token' => 'twitter token',
|
||||
'oauth_token_secret' => 'token secret',
|
||||
));
|
||||
|
||||
$provider->getTwitterClient()->expects($this->once())
|
||||
->method('request')
|
||||
->will($this->returncallback(function () use ($provider) {
|
||||
$provider->getTwitterClient()->response = array(
|
||||
'response' => json_encode(array(
|
||||
'screen_name' => self::USERNAME,
|
||||
'profile_image_url_https' => self::IMAGEURL,
|
||||
'id' => self::ID,
|
||||
))
|
||||
);
|
||||
|
||||
return 200;
|
||||
}));
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function getAvailableFieldsForIdentity()
|
||||
{
|
||||
return array(
|
||||
Identity::PROPERTY_ID => self::ID,
|
||||
Identity::PROPERTY_USERNAME => self::USERNAME,
|
||||
Identity::PROPERTY_IMAGEURL => self::IMAGEURL,
|
||||
);
|
||||
}
|
||||
|
||||
protected function getProviderForFailingIdentity()
|
||||
{
|
||||
return $this->provideFailingProvider();
|
||||
}
|
||||
|
||||
protected function provideFailingProvider()
|
||||
{
|
||||
$provider = $this->getProvider();
|
||||
|
||||
return $provider;
|
||||
}
|
||||
|
||||
protected function authenticate(ProviderInterface $provider)
|
||||
{
|
||||
$provider->getSession()->set('twitter.provider.id', '12345');
|
||||
}
|
||||
|
||||
protected function getProvider()
|
||||
{
|
||||
$twitter = $this->getMockBuilder('tmhOAuth')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$twitter->config = $this->getTestOptions();
|
||||
|
||||
return new Twitter($this->getUrlGeneratorMock(), $this->getMockSession(), $twitter);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user