mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-24 10:23:17 +00:00
port authorize with providers
This commit is contained in:
@@ -50,13 +50,15 @@ class Facebook extends AbstractProvider
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function authenticate()
|
public function authenticate(array $params = array())
|
||||||
{
|
{
|
||||||
|
$params = array_merge(['providerId' => $this->getId()], $params);
|
||||||
|
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->facebook->getRedirectLoginHelper()->getLoginUrl(
|
$this->facebook->getRedirectLoginHelper()->getLoginUrl(
|
||||||
$this->generator->generate(
|
$this->generator->generate(
|
||||||
'login_authentication_provider_callback',
|
'login_authentication_provider_callback',
|
||||||
['providerId' => $this->getId()],
|
$params,
|
||||||
UrlGenerator::ABSOLUTE_URL
|
UrlGenerator::ABSOLUTE_URL
|
||||||
),
|
),
|
||||||
['email']
|
['email']
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ class Github extends AbstractProvider
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function authenticate()
|
public function authenticate(array $params = array())
|
||||||
{
|
{
|
||||||
|
$params = array_merge(['providerId' => $this->getId()], $params);
|
||||||
|
|
||||||
$state = $this->createState();
|
$state = $this->createState();
|
||||||
|
|
||||||
$this->session->set('github.provider.state', $state);
|
$this->session->set('github.provider.state', $state);
|
||||||
@@ -90,7 +92,7 @@ class Github extends AbstractProvider
|
|||||||
'state' => $state,
|
'state' => $state,
|
||||||
'redirect_uri' => $this->generator->generate(
|
'redirect_uri' => $this->generator->generate(
|
||||||
'login_authentication_provider_callback',
|
'login_authentication_provider_callback',
|
||||||
['providerId' => $this->getId()],
|
$params,
|
||||||
UrlGenerator::ABSOLUTE_URL
|
UrlGenerator::ABSOLUTE_URL
|
||||||
),
|
),
|
||||||
], '', '&'));
|
], '', '&'));
|
||||||
|
|||||||
@@ -41,14 +41,6 @@ class GooglePlus extends AbstractProvider
|
|||||||
'https://www.googleapis.com/auth/userinfo.profile',
|
'https://www.googleapis.com/auth/userinfo.profile',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->client->setRedirectUri(
|
|
||||||
$this->generator->generate(
|
|
||||||
'login_authentication_provider_callback', [
|
|
||||||
'providerId' => $this->getId(),
|
|
||||||
], UrlGenerator::ABSOLUTE_URL
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->client->setApprovalPrompt("auto");
|
$this->client->setApprovalPrompt("auto");
|
||||||
|
|
||||||
if ($this->session->has('google-plus.provider.token')) {
|
if ($this->session->has('google-plus.provider.token')) {
|
||||||
@@ -115,8 +107,18 @@ class GooglePlus extends AbstractProvider
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function authenticate()
|
public function authenticate(array $params = array())
|
||||||
{
|
{
|
||||||
|
$params = array_merge(['providerId' => $this->getId()], $params);
|
||||||
|
|
||||||
|
$this->client->setRedirectUri(
|
||||||
|
$this->generator->generate(
|
||||||
|
'login_authentication_provider_callback',
|
||||||
|
$params,
|
||||||
|
UrlGenerator::ABSOLUTE_URL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
$state = $this->createState();
|
$state = $this->createState();
|
||||||
|
|
||||||
$this->session->set('google-plus.provider.state', $state);
|
$this->session->set('google-plus.provider.state', $state);
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ class Linkedin extends AbstractProvider
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function authenticate()
|
public function authenticate(array $params = array())
|
||||||
{
|
{
|
||||||
|
$params = array_merge(['providerId' => $this->getId()], $params);
|
||||||
|
|
||||||
$state = $this->createState();
|
$state = $this->createState();
|
||||||
|
|
||||||
$this->session->set('linkedin.provider.state', $state);
|
$this->session->set('linkedin.provider.state', $state);
|
||||||
@@ -91,7 +93,7 @@ class Linkedin extends AbstractProvider
|
|||||||
'state' => $state,
|
'state' => $state,
|
||||||
'redirect_uri' => $this->generator->generate(
|
'redirect_uri' => $this->generator->generate(
|
||||||
'login_authentication_provider_callback',
|
'login_authentication_provider_callback',
|
||||||
['providerId' => $this->getId()],
|
$params,
|
||||||
UrlGenerator::ABSOLUTE_URL
|
UrlGenerator::ABSOLUTE_URL
|
||||||
),
|
),
|
||||||
], '', '&'));
|
], '', '&'));
|
||||||
|
|||||||
@@ -43,9 +43,11 @@ interface ProviderInterface
|
|||||||
/**
|
/**
|
||||||
* Redirects to the actual authentication provider
|
* Redirects to the actual authentication provider
|
||||||
*
|
*
|
||||||
|
* @param array $params
|
||||||
|
*
|
||||||
* @return RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function authenticate();
|
public function authenticate(array $params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logout from the provider, removes the token if possible
|
* Logout from the provider, removes the token if possible
|
||||||
|
|||||||
@@ -69,14 +69,16 @@ class Twitter extends AbstractProvider
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function authenticate()
|
public function authenticate(array $params = array())
|
||||||
{
|
{
|
||||||
|
$params = array_merge(['providerId' => $this->getId()], $params);
|
||||||
|
|
||||||
$code = $this->twitter->request(
|
$code = $this->twitter->request(
|
||||||
'POST',
|
'POST',
|
||||||
$this->twitter->url('oauth/request_token', ''),
|
$this->twitter->url('oauth/request_token', ''),
|
||||||
['oauth_callback' => $this->generator->generate(
|
['oauth_callback' => $this->generator->generate(
|
||||||
'login_authentication_provider_callback',
|
'login_authentication_provider_callback',
|
||||||
['providerId' => $this->getId()],
|
$params,
|
||||||
UrlGenerator::ABSOLUTE_URL
|
UrlGenerator::ABSOLUTE_URL
|
||||||
)]
|
)]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -79,8 +79,10 @@ class Viadeo extends AbstractProvider
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function authenticate()
|
public function authenticate(array $params = array())
|
||||||
{
|
{
|
||||||
|
$params = array_merge(['providerId' => $this->getId()], $params);
|
||||||
|
|
||||||
$state = $this->createState();
|
$state = $this->createState();
|
||||||
|
|
||||||
$this->session->set('viadeo.provider.state', $state);
|
$this->session->set('viadeo.provider.state', $state);
|
||||||
@@ -91,7 +93,7 @@ class Viadeo extends AbstractProvider
|
|||||||
'response_type' => 'code',
|
'response_type' => 'code',
|
||||||
'redirect_uri' => $this->generator->generate(
|
'redirect_uri' => $this->generator->generate(
|
||||||
'login_authentication_provider_callback',
|
'login_authentication_provider_callback',
|
||||||
['providerId' => $this->getId()],
|
$params,
|
||||||
UrlGenerator::ABSOLUTE_URL
|
UrlGenerator::ABSOLUTE_URL
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
|||||||
@@ -167,6 +167,103 @@ class OAuth2Controller extends Controller
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function authorizeWithProviderAction(Request $request, $providerId)
|
||||||
|
{
|
||||||
|
$context = new Context(Context::CONTEXT_OAUTH2_NATIVE);
|
||||||
|
$this->dispatch(PhraseaEvents::PRE_AUTHENTICATE, new PreAuthenticate($request, $context));
|
||||||
|
|
||||||
|
//Check for auth params, send error or redirect if not valid
|
||||||
|
$params = $this->oAuth2Adapter->getAuthorizationRequestParameters($request);
|
||||||
|
|
||||||
|
/** @var ApiApplicationRepository $appRepository */
|
||||||
|
$appRepository = $this->app['repo.api-applications'];
|
||||||
|
if (null === $client = $appRepository->findByClientId($params['client_id'])) {
|
||||||
|
throw new NotFoundHttpException(sprintf('Application with client id %s could not be found', $params['client_id']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$provider = $this->findProvider($providerId);
|
||||||
|
|
||||||
|
return $provider->authenticate($request->query->all());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeCallbackAction(Request $request, $providerId)
|
||||||
|
{
|
||||||
|
$context = new Context(Context::CONTEXT_OAUTH2_NATIVE);
|
||||||
|
$provider = $this->findProvider($providerId);
|
||||||
|
$params = $this->oAuth2Adapter->getAuthorizationRequestParameters($request);
|
||||||
|
|
||||||
|
// triggers what's necessary
|
||||||
|
try {
|
||||||
|
$provider->onCallback($request);
|
||||||
|
$token = $provider->getToken();
|
||||||
|
} catch (NotAuthenticatedException $e) {
|
||||||
|
$this->getSession()->getFlashBag()->add('error', $this->app->trans('Unable to authenticate with %provider_name%', ['%provider_name%' => $provider->getName()]));
|
||||||
|
|
||||||
|
return $this->app->redirectPath('oauth2_authorize', array_merge(array('error' => 'login'), $params));
|
||||||
|
}
|
||||||
|
|
||||||
|
$userAuthProvider = $this->getUserAuthProviderRepository()
|
||||||
|
->findWithProviderAndId($token->getProvider()->getId(), $token->getId());
|
||||||
|
|
||||||
|
if($userAuthProvider == null){
|
||||||
|
unset($params['state']);
|
||||||
|
|
||||||
|
return $this->app->redirectPath('oauth2_authorize', array_merge(array('error' => 'login'), $params));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$user = $this->getAuthenticationSuggestionFinder()->find($token);
|
||||||
|
} catch (NotAuthenticatedException $e) {
|
||||||
|
$this->app->addFlash('error', $this->app->trans('Unable to retrieve provider identity'));
|
||||||
|
|
||||||
|
return $this->app->redirectPath('oauth2_authorize', array_merge(array('error' => 'login'), $params));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getAuthenticator()->openAccount($userAuthProvider->getUser());
|
||||||
|
$event = new PostAuthenticate($request, new Response(), $user, $context);
|
||||||
|
$this->dispatch(PhraseaEvents::POST_AUTHENTICATE, $event);
|
||||||
|
|
||||||
|
/** @var ApiApplicationRepository $appRepository */
|
||||||
|
$appRepository = $this->app['repo.api-applications'];
|
||||||
|
if (null === $client = $appRepository->findByClientId($params['client_id'])) {
|
||||||
|
throw new NotFoundHttpException(sprintf('Application with client id %s could not be found', $params['client_id']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->oAuth2Adapter->setClient($client);
|
||||||
|
|
||||||
|
//check if current client is already authorized by current user
|
||||||
|
$clients = $appRepository->findAuthorizedAppsByUser($this->getAuthenticatedUser());
|
||||||
|
$appAuthorized = false;
|
||||||
|
|
||||||
|
foreach ($clients as $authClient) {
|
||||||
|
if ($client->getClientId() == $authClient->getClientId()) {
|
||||||
|
$appAuthorized = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$account = $this->oAuth2Adapter->updateAccount($this->getAuthenticatedUser());
|
||||||
|
|
||||||
|
$params['account_id'] = $account->getId();
|
||||||
|
|
||||||
|
//if native app show template
|
||||||
|
if ($this->oAuth2Adapter->isNativeApp($params['redirect_uri'])) {
|
||||||
|
$params = $this->oAuth2Adapter->finishNativeClientAuthorization($appAuthorized, $params);
|
||||||
|
|
||||||
|
$r = new Response($this->render("api/auth/native_app_access_token.html.twig", $params));
|
||||||
|
$r->headers->set('Content-Type', 'text/html');
|
||||||
|
|
||||||
|
return $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->oAuth2Adapter->finishClientAuthorization($appAuthorized, $params);
|
||||||
|
|
||||||
|
// As OAuth2 library already outputs response content, we need to send an empty
|
||||||
|
// response to avoid breaking silex controller
|
||||||
|
return '';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TOKEN ENDPOINT
|
* TOKEN ENDPOINT
|
||||||
* Token endpoint - used to exchange an authorization grant for an access token.
|
* Token endpoint - used to exchange an authorization grant for an access token.
|
||||||
@@ -206,4 +303,41 @@ class OAuth2Controller extends Controller
|
|||||||
{
|
{
|
||||||
return $this->app['manipulator.api-account'];
|
return $this->app['manipulator.api-account'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $providerId
|
||||||
|
* @return ProviderInterface
|
||||||
|
*/
|
||||||
|
private function findProvider($providerId)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->getAuthenticationProviders()->get($providerId);
|
||||||
|
} catch (InvalidArgumentException $e) {
|
||||||
|
throw new NotFoundHttpException('The requested provider does not exist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ProvidersCollection
|
||||||
|
*/
|
||||||
|
private function getAuthenticationProviders()
|
||||||
|
{
|
||||||
|
return $this->app['authentication.providers'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return UsrAuthProviderRepository
|
||||||
|
*/
|
||||||
|
private function getUserAuthProviderRepository()
|
||||||
|
{
|
||||||
|
return $this->app['repo.usr-auth-providers'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return SuggestionFinder
|
||||||
|
*/
|
||||||
|
private function getAuthenticationSuggestionFinder()
|
||||||
|
{
|
||||||
|
return $this->app['authentication.suggestion-finder'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,12 @@ use Silex\Application;
|
|||||||
use Silex\ControllerCollection;
|
use Silex\ControllerCollection;
|
||||||
use Silex\ControllerProviderInterface;
|
use Silex\ControllerProviderInterface;
|
||||||
use Silex\ServiceProviderInterface;
|
use Silex\ServiceProviderInterface;
|
||||||
|
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
|
||||||
|
|
||||||
class OAuth2 extends Api implements ControllerProviderInterface, ServiceProviderInterface
|
class OAuth2 extends Api implements ControllerProviderInterface, ServiceProviderInterface
|
||||||
{
|
{
|
||||||
|
use ControllerProviderTrait;
|
||||||
|
|
||||||
public function register(Application $app)
|
public function register(Application $app)
|
||||||
{
|
{
|
||||||
$app['controller.oauth2'] = $app->share(function (PhraseaApplication $app) {
|
$app['controller.oauth2'] = $app->share(function (PhraseaApplication $app) {
|
||||||
@@ -35,6 +38,16 @@ class OAuth2 extends Api implements ControllerProviderInterface, ServiceProvider
|
|||||||
|
|
||||||
public function connect(Application $app)
|
public function connect(Application $app)
|
||||||
{
|
{
|
||||||
|
$firewall = $this->getFirewall($app);
|
||||||
|
|
||||||
|
$requireUnauthenticated = function () use ($firewall) {
|
||||||
|
if (null !== $response = $firewall->requireNotAuthenticated()) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
if (! $this->isApiEnabled($app)) {
|
if (! $this->isApiEnabled($app)) {
|
||||||
return $app['controllers_factory'];
|
return $app['controllers_factory'];
|
||||||
}
|
}
|
||||||
@@ -48,6 +61,15 @@ class OAuth2 extends Api implements ControllerProviderInterface, ServiceProvider
|
|||||||
|
|
||||||
$controllers->post('/token', 'controller.oauth2:tokenAction');
|
$controllers->post('/token', 'controller.oauth2:tokenAction');
|
||||||
|
|
||||||
|
$controllers->get('/provider/{providerId}/authorize/', 'controller.oauth2:authorizeWithProviderAction')
|
||||||
|
->before($requireUnauthenticated)
|
||||||
|
->bind('oauth2_provider_authorize');
|
||||||
|
|
||||||
|
// AuthProviders callbacks
|
||||||
|
$controllers->get('/provider/{providerId}/callback/', 'controller.oauth2:authorizeCallbackAction')
|
||||||
|
->before($requireUnauthenticated)
|
||||||
|
->bind('login_authentication_provider_callback');
|
||||||
|
|
||||||
return $controllers;
|
return $controllers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,26 @@
|
|||||||
<input id="myPass" name="password" class="span6" type="password" placeholder="{{ 'admin::compte-utilisateur mot de passe' | trans }}" />
|
<input id="myPass" name="password" class="span6" type="password" placeholder="{{ 'admin::compte-utilisateur mot de passe' | trans }}" />
|
||||||
<input id="button_login" name="action_login" class="btn btn-inverse btn-large span6" type="submit" value="{{ 'Se connecter' | trans }}" />
|
<input id="button_login" name="action_login" class="btn btn-inverse btn-large span6" type="submit" value="{{ 'Se connecter' | trans }}" />
|
||||||
</form>
|
</form>
|
||||||
|
<div class="well-large">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="text-center">
|
||||||
|
{{ "Or login with" | trans }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="text-center">
|
||||||
|
<ul class="unstyled inline provider-list">
|
||||||
|
{% for provider in app['authentication.providers'] %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('oauth2_provider_authorize', { 'providerId' : provider.getId() }|merge(app.request.query.all)) }}">
|
||||||
|
<img src="{{ provider.getIconURI() }}" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<a href="#">{{ 'Problemes de connexion ?' | trans }}</a>
|
<a href="#">{{ 'Problemes de connexion ?' | trans }}</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user