Commit a2e99e87 authored by Patrick Barroca's avatar Patrick Barroca 🤞

Merge branch 'dev#106075_explo_france_connect_avec_identifiant_gpsea' into 'master'

Dev#106075 explo france connect avec identifiant gpsea

See merge request !3432
parents d4f91f5b 8fbf9e0a
Pipeline #9676 passed with stage
in 46 minutes and 57 seconds
......@@ -16,6 +16,9 @@
[submodule "library/matomo-php-tracker"]
path = library/matomo-php-tracker
url = https://git.afi-sa.net/afi/matomo-php-tracker.git
[submodule "library/php-jwt"]
path = library/php-jwt
url = https://git.afi-sa.net/afi/php-jwt.git
[submodule "library/phpseclib"]
path = library/phpseclib
url = https://git.afi-sa.net/afi/phpseclib.git
......
'106075' =>
['Label' => $this->_('Serveurs d\'identité tiers'),
'Desc' => $this->_('Bokeh permet aux abonnés d\'associer leurs comptes FranceConnect, Google et plus généralement OpenId à leur compte Bokeh.'),
'Image' => '',
'Video' => 'https://youtu.be/sRC3dO70ezI',
'Category' => $this->_('Compte lecteur'),
'Right' => function($feature_description, $user) {return true;},
'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=FranceConnect_OpenId',
'Test' => '',
'Date' => '2020-02-27'],
\ No newline at end of file
- ticket #106075 : Compte lecteur : Ajout de la prise en charge de serveurs d'identité tiers France Connect, Google et plus généralement OpenId
\ No newline at end of file
<?php
/**
* Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Admin_IdentityProvidersController extends ZendAfi_Controller_Action {
public function getPlugins() {
return ['ZendAfi_Controller_Plugin_ResourceDefinition_IdentityProvider',
'ZendAfi_Controller_Plugin_Manager_IdentityProvider'];
}
public function indexAction() {
parent::indexAction();
$this->view->titre = $this->_('Fournisseurs d\'identité');
}
}
?>
\ No newline at end of file
<?php
echo $this
->tag('div',
$this->tag('dl',
$this->tag('dt', $this->_('Url de retour :'))
. $this->tag('dd', $this->provider->getCallBackUrl())),
['class' => 'content_edit_head']);
echo $this->renderForm($this->form);
<?php
echo $this->Button_New((new Class_Entity())
->setText($this->_('Ajouter un fournisseur d\'identité')));
echo $this
->renderTable((new Class_TableDescription('providers'))
->addColumn($this->_('Libellé'), ['attribute' => 'label'])
->addColumn($this->_('Url de retour'), ['attribute' => 'callback_url'])
->addColumn($this->_('Actif ?'),
function($model)
{
return $model->getActive()
? $this->_('Oui')
: $this->_('Non');
})
->addRowAction(function($model) { return $this->renderPluginsActions($model); }),
$this->providers);
......@@ -1225,6 +1225,26 @@ class AbonneController extends ZendAfi_Controller_Action {
}
public function associatedProvidersAction() {
$this->view->titre = $this->_('Mes comptes associés');
$this->view->identities = Class_User_Identity::findIdentitiesForActiveProviders($this->_user);
}
public function dissociateProviderAction() {
if ((!$identity = Class_User_Identity::find((int)$this->_getParam('id')))
|| $this->_user->getId() != $identity->getUserId()) {
$this->_helper->notify($this->_('Impossible de dissocier une identité inconnue'));
return $this->_redirectToUrlOrReferer('/');
}
$identity->dissociate();
$this->_helper->notify($this->_('Votre compte a été dissocié de %s',
$identity->getProviderLabel()));
$this->_redirectToUrlOrReferer('/');
}
public function unlinkCardAction() {
return $this->_unlinkCard(['parent_id' => $this->_user->getId(),
'child_id' => (int)$this->_getParam('id')],
......
......@@ -42,21 +42,6 @@ class AuthController extends ZendAfi_Controller_Action {
}
public function isLectura() {
return $this->_getParam('lectura', false);
}
public function isCasRequest() {
return strlen($this->getCasServerUrl())>0;
}
public function getCasServerUrl() {
return $this->_request->getParam('service');
}
public function getErrorMessages($error_code) {
$messages = [static::LOST_PASS_NOLOGIN => $this->_('Veuillez saisir votre identifiant.'),
static::LOST_PASS_NOUSER => $this->_('Identifiant inconnu.'),
......@@ -183,19 +168,19 @@ class AuthController extends ZendAfi_Controller_Action {
$this->view->service = $service;
$this->view->titreAdd($this->view->_('Connexion'));
$this->view->title = Class_Users::getIdentity()
? $this->view->preferences['titre_connecte']
: $this->view->preferences['titre'];
$strategy = Auth_Strategy_Abstract::strategyForController($this);
$strategy = Class_Auth_Strategy::newFor($this);
$strategy->setDefaultUrl($redirect);
$strategy
->onLoginSuccess(function($user)
{
$user->registerNotificationsOn($this->getHelper('notify')->bePopup());
});
$strategy->processLogin();
$this->view->form_action = 'login';
$this->view->title = $strategy->getPageTitle($this->view);
$this->view->message = $strategy->getMessage($this->view);
$this->view->form_action = $this->view->url($strategy->getFormAction($this->view->id_module));
}
......@@ -205,7 +190,7 @@ class AuthController extends ZendAfi_Controller_Action {
$this->view->preferences = $this->_loginPrefFromWidgetOrModule();
Auth_Strategy_Abstract::strategyForController($this)
Class_Auth_Strategy::newFor($this)
->disableRedirect()
->onLoginSuccess(function($user) use ($redirect, $location)
{
......@@ -243,7 +228,7 @@ class AuthController extends ZendAfi_Controller_Action {
$this->getHelper('ViewRenderer')->setLayoutScript('subModal.phtml');
$redirect_uri = $this->_getParam('redirect_uri');
$strategy = new Auth_Strategy_OAuth($this);
$strategy = new Class_Auth_OAuth($this);
$strategy->processLogin();
}
......@@ -277,7 +262,7 @@ class AuthController extends ZendAfi_Controller_Action {
? $target->getUrl()
: $referer;
$strategy = Auth_Strategy_Abstract::strategyForController($this);
$strategy = Class_Auth_Strategy::newFor($this);
$strategy->setDefaultUrl($url);
$on_fail = function() use($strategy, $referer) {
$strategy->setRedirectUrl($referer);
......@@ -289,15 +274,12 @@ class AuthController extends ZendAfi_Controller_Action {
$user->registerNotificationsOn($this->getHelper('notify')->bePopup());
};
$strategy->onLoginSuccess($on_success);
$strategy->processLogin();
}
public function logoutAction() {
ZendAfi_Auth::getInstance()->clearIdentity();
$profil = Class_Profil::getCurrentProfil();
$this->_redirectToLogoutProfil($profil->getModuleAccueilPreferencesByType('LOGIN'));
Class_Auth_Strategy::newFor($this)->logout();
}
......@@ -650,272 +632,3 @@ class AuthController extends ZendAfi_Controller_Action {
$this->_redirectToUrlOrReferer('/opac/index/index');
}
}
abstract class Auth_Strategy_Abstract {
protected
$redirect_url = '',
$disable_redirect = false,
$on_login_success_callback,
$on_login_fail_callback;
static public function strategyForController($controller) {
if ($controller->isCasRequest() && static::isLogged())
return new Auth_Strategy_Cas_Logged($controller);
if ($controller->isCasRequest() && !static::isLogged())
return new Auth_Strategy_Cas_NotLogged($controller);
if ($controller->isLectura())
return new Auth_Strategy_Lectura($controller);
if (static::isLogged())
return new Auth_Strategy_Logged($controller);
return new Auth_Strategy_NotLogged($controller);
}
static protected function isLogged() {
return Class_Users::getIdentity();
}
public function disableRedirect() {
$this->disable_redirect = true;
return $this;
}
public function __construct($controller) {
$this->controller = $controller;
$this->default_url = $this->controller->getRedirectDefaultUrl();
}
public function getRequest(){
return $this->controller->getRequest();
}
public function processLogin() {
$this->prepareLogin();
if (!$this->getRequest()->isPost())
return $this->_handleRedirect();
$callback = $this->_handlePost();
$password_not_secure = Class_WebService_SIGB_Nanook_PatronPasswordNotSecure::getInstance();
if (($message = $password_not_secure->getMessage())
&& !$this->controller->view->isPopup())
return $this->controller->onPasswordNotSecure($message,
$password_not_secure->getPattern());
$callback();
return $this->_handleRedirect();
}
protected function _handleRedirect() {
if ($this->shouldRedirect())
$this->controller->redirect($this->redirect_url);
return $this;
}
public function setDefaultUrl($url) {
$this->default_url = $url;
}
public function prepareLogin() {
}
/** @codeCoverageIgnore */
protected function _handlePost() {
return function() {};
}
public function shouldRedirect() {
return ($this->getRedirectUrl()!='');
}
public function getRedirectUrl() {
if ($this->disable_redirect)
return '';
return $this->redirect_url;
}
public function setRedirectUrl($url) {
$this->redirect_url = $url;
return $this;
}
public function onLoginSuccess($do) {
$this->on_login_success_callback = $do;
return $this;
}
public function onLoginFail($do) {
$this->on_login_fail_callback = $do;
return $this;
}
protected function _doOnLoginFail() {
if (isset($this->on_login_fail_callback))
call_user_func($this->on_login_fail_callback);
return $this;
}
protected function _doOnLoginSuccess() {
if (($user = Class_Users::getIdentity()) && isset($this->on_login_success_callback))
call_user_func($this->on_login_success_callback, $user);
return $this;
}
}
class Auth_Strategy_NotLogged extends Auth_Strategy_Abstract{
protected function _handlePost() {
$this->redirect_url = $this->default_url;
if (!$error = $this->controller->_authenticate())
return function() { return $this->_doOnLoginSuccess(); };
return function() use($error) {
$this->controller->notify($error);
return $this->_doOnLoginFail();
};
}
}
class Auth_Strategy_Logged extends Auth_Strategy_Abstract{
}
class Auth_Strategy_Cas_Abstract extends Auth_Strategy_Abstract{
public function urlServiceCas() {
if ($url_musicme = $this->redirectMusicme())
return $url_musicme;
$ticket = (new Class_CasTicket())->getTicketForCurrentUser();
$queries = [];
$url_cas = array_merge(['query'=> '', 'path' => ''],
parse_url($this->controller->getCasServerUrl()));
parse_str($url_cas['query'], $queries);
$queries['ticket'] = $ticket;
$path = $url_cas['path'] ? $url_cas['path'] : '';
$scheme = $url_cas['scheme'] ? $url_cas['scheme'] : 'http';
return $scheme . '://' . $url_cas['host'] . $path . '?' . http_build_query($queries);
}
public function redirectMusicme() {
if (strpos($this->controller->getCasServerUrl(),'musicme') !== false)
return Musicme_Config::getInstance()->getSsoUrl(Class_Users::getIdentity());
return false;
}
}
class Auth_Strategy_Cas_Logged extends Auth_Strategy_Cas_Abstract{
public function prepareLogin() {
if ($this->isCasDeconnected())
return $this->redirect_url='/opac';
$this->redirect_url=$this->urlServiceCas();
}
protected function isCasDeconnected() {
return stristr($this->controller->getCasServerUrl(),'deconnexion=ok') != FALSE;
}
}
class Auth_Strategy_Cas_NotLogged extends Auth_Strategy_Cas_Abstract{
protected function _handlePost() {
if ($error = $this->controller->_authenticate())
return function() use($error) { return $this->controller->notify($error); };
$this->redirect_url = $this->urlServiceCas();
return function() {};
}
}
class Auth_Strategy_Lectura extends Auth_Strategy_Abstract {
protected function _handlePost() {
$this->controller->getHelper('ViewRenderer')->setNoRender();
$response = $this->controller->getResponse();
$view = $this->controller->view;
$request = $this->controller->getRequest();
$response->setHeader('Content-Type', 'application/xml;charset=utf-8');
$login = $request->getPost('CAB');
$password = $request->getPost('PWD');
$response->setBody($this->getXmlResponse($view,
ZendAfi_Auth::getInstance()->authenticateLoginPassword($login, $password)));
return function() {};
}
protected function getXmlResponse($view,$is_success=true) {
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".
$view->tag('libraryuserauth',
$view->tag('returncode',$is_success? 'success':'error'),
['timestamp' => date('Ymd-his')]);
}
}
class Auth_Strategy_OAuth extends Auth_Strategy_NotLogged {
protected function _handlePost() {
parent::_handlePost();
if (!$user = Class_Users::getIdentity())
return function() {};
$request = $this->controller->getRequest();
$token = Class_User_ApiToken::findOrCreateForUserAndApplication($user,
$request->getParam('client_id'));
$this->redirect_url = sprintf('%s#token=%s',
$request->getParam('redirect_uri'),
$token->getToken());
return function() {};
}
}
\ No newline at end of file
<?php
/**
* Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class IdentityProvidersController extends ZendAfi_Controller_Action {
public function authenticateAction() {
if (!Class_AdminVar::isIdentityProvidersEnabled())
throw new Zend_Controller_Action_Exception($this->_('Désolé, cette page n\'existe pas'), 404);
if (!$provider = Class_IdentityProvider::find((int)$this->_getParam('id'))) {
$this->_helper->notify($this->_('Impossible de s\'identifier à un service inconnu'));
return $this->_redirectToReferer();
}
if (!$url = $provider->loginUrl($this->_getParam('redirect', ''))) {
$this->_helper->notify($this->_('Impossible de déterminer l\'url de login pour %s',
$provider->getLabel()));
return $this->_redirectToReferer();
}
$provider->setLoginSuccessRedirectUrl($this->_getReferer());
$this->_redirect($url);
}
public function logoutAction() {
if (!$provider = Class_IdentityProvider::find((int)$this->_getParam('id')))
return $this->_redirectToReferer();
$this->_redirect($provider->logoutUrl());
}
}
<?php
$this->openBoite($this->titre);
echo $this->abonne_AssociatedProvidersBoard($this->identities);
$this->closeBoite();
echo $this->abonne_RetourFiche();
......@@ -2,6 +2,7 @@
$action = ['controller' => 'auth',
'action' => 'ajax-login'];
if ($this->isPopup())
$action['render'] = 'popup';
......@@ -12,3 +13,6 @@ echo $this->Widget_Login(new Class_Entity(array_merge(['Preferences' => $this->
'action' => $this->url($action, null, true)
. ($this->location ? '?location=' . $this->location : '')]])));
echo $this->identityProviders();
<?php
$url_action = $this->form_action ?
$this->form_action : $this->url(['controller' => 'auth',
'action' => ('boite-login'),