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

dev #79874 : identity providers with types

parent 9d8fde42
Pipeline #8787 failed with stage
in 34 minutes and 3 seconds
<?php echo $this->renderForm($this->form); ?>
<?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);
......@@ -4,6 +4,7 @@ echo $this->Button_New((new Class_Entity())->setText($this->_('Ajouter un fourni
echo $this->renderTable(
(new Class_TableDescription('providers'))
->addColumn($this->_('Libellé'), ['attribute' => 'label'])
->addColumn($this->_('Libellé'), ['attribute' => 'label'])
->addColumn($this->_('Url de retour'), ['attribute' => 'callback_url'])
->addRowAction(function($model) { return $this->renderPluginsActions($model); }),
$this->providers);
......@@ -42,27 +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 isOpenidRequest() {
return $this->_request->getParam('code') &&
$this->_request->getParam('state');
}
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.'),
......@@ -190,7 +169,7 @@ class AuthController extends ZendAfi_Controller_Action {
$this->view->titreAdd($this->view->_('Connexion'));
$strategy = Auth_Strategy_Abstract::strategyForController($this);
$strategy = Class_Auth_Strategy::newFor($this);
$strategy->setDefaultUrl($redirect);
$strategy
->onLoginSuccess(function($user)
......@@ -207,9 +186,7 @@ class AuthController extends ZendAfi_Controller_Action {
public function dissociateAction() {
$identifier = $this->_getParam('identifier',Class_User_Identity::getUserOpenId());
if (! $identity = Class_User_Identity::findFirstBy(['user_id' => Class_Users::getIdentity()->getId(),
'identifier' => $identifier]))
if (!$identity = Class_User_Identity::find((int)$this->_getParam('id')))
return $this->_redirectToUrlOrReferer('/');
$identity->dissociate();
......@@ -224,7 +201,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)
{
......@@ -261,7 +238,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();
}
......@@ -295,7 +272,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);
......@@ -312,8 +289,7 @@ class AuthController extends ZendAfi_Controller_Action {
public function logoutAction() {
$strategy = Auth_Strategy_Abstract::strategyForController($this);
$strategy->logout();
Class_Auth_Strategy::newFor($this)->logout();
}
......@@ -668,480 +644,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 ($controller->isOpenidRequest())
return new Auth_Strategy_Openid_NotLogged($controller);
if (Class_User_Identity::isLogged())
return new Auth_Strategy_Openid_Logged($controller);
if (static::isLogged())
return new Auth_Strategy_Logged($controller);
return new Auth_Strategy_NotLogged($controller);
}
protected function _getProfilRedirectUrl() {
$profil = Class_Profil::getCurrentProfil();
$preferences = $profil->getModuleAccueilPreferencesByType('LOGIN');
$target = isset($preferences['profil_logout_redirect'])
? (int) $preferences['profil_logout_redirect']
: 0;
if (0 < $target)
return '/opac/index/index/id_profil/' . $target;
return $profil->hasParentProfil()
? '/opac/index/index/id_profil/' . $profil->getParentProfil()->getId()
: '/';
}
public function logout() {
ZendAfi_Auth::getInstance()->clearIdentity();
$this->controller->redirect($this->_getProfilRedirectUrl());
}
public function getMessage($view) {
return '';
}
protected function _getParam($name) {
return $this->controller->getRequest()->getParam($name);
}
static protected function isLogged() {
return Class_Users::getIdentity();
}
public function getPageTitle($view) {
return $view->preferences['titre'];
}
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 getFormAction($id_module) {
return ['controller' => 'auth',
'action' => 'login',
'id_module' => $id_module];
}
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{
public function getPageTitle($view) {
return $view->preferences['titre_connecte'];
}
}
class Auth_Strategy_Openid_Logged extends Auth_Strategy_Logged {
public function logout() {
if (!$provider = Class_IdentityProvider::findFromProvider($this->_getParam('provider'))) {
Class_OpenId::clearSession();
return parent::logout();
}
$openid = new Class_OpenId($provider);
$redirect_url = $openid->getLogoutUrl($this->_getProfilRedirectUrl());
$openid->clearSession();
ZendAfi_Auth::getInstance()->clearIdentity();
$this->controller->redirect($redirect_url);
}
}
class Auth_Strategy_Openid_NotLogged extends Auth_Strategy_NotLogged {
protected
$_provider,
$_infos;
public function getPageTitle($view) {
return $view->_('Associer votre compte');
}
public function getMessage($view) {
if (! ($provider = $this->_getProvider()))
return '';
if (!Class_Users::getIdentity())
return $view->_('Vous êtes connecté à %s en tant que %s. Pour votre première connexion, veuillez saisir les identifiants de votre abonnement.',
$this->_getProvider()->getLabel(),
$this->getUserInfos() ? $this->getUserInfos()->name : '' );
return $view->_('Vous êtes connecté à %s en tant que %s. ',
$this->_getProvider()->getLabel(),
$this->getUserInfos() ? $this->getUserInfos()->name : '' );
}
protected function getUserInfos() {
if ($this->_infos)
return $this->_infos;
$code = $this->_getParam('code');
$state = $this->_getParam('state');
return ($this->_infos = (new Class_OpenId($this->_getProvider()))->getUserInfos($code,$state));
}
protected function _doOnLoginSuccess() {
$code = $this->_getParam('code');
$state = $this->_getParam('state');
if (!$provider = $this->_getProvider()) {
$this->controller->notify($this->controller->view->_('Association de compte impossible'));
return parent::_doOnLoginSuccess();
}
$openid = (new Class_OpenId($provider));
if ((!$this->_infos = $openid->getUserInfos($code,$state))
|| (!$user_open_id = Class_User_Identity::getUserOpenId())) {
$this->controller->notify($this->controller->view->_('L\'association de compte vers "%s" a échoué',
$provider->getLibelle()));
return parent::_doOnLoginSuccess();
}
$this->setRedirectUrl($openid->getRedirectUrl());
Class_User_Identity::findOrCreateForUserAndApplication(Class_Users::getIdentity(),
$provider,
$user_open_id);
return parent::_doOnLoginSuccess();
}
protected function _doOnLoginFail() {
$this->redirect_url = '';
}
public function getFormAction($id_module) {
$code = $this->_getParam('code');
$state = $this->_getParam('state');
return ['controller' => 'auth',
'action' => 'login',
'code' => $code,
'state' => $state,
'id_module' => $id_module];
}
protected function _getProvider() {
return isset($this->_provider)
? $this->_provider
: $this->_provider = Class_IdentityProvider::findFromProvider($this->_getParam('provider'));
}
protected function _handleRedirect() {
$code = $this->_getParam('code');
$state = $this->_getParam('state');
if (! $provider = $this->_getProvider())
return function() {};
$openid = new Class_OpenId($provider);
if (!$this->_infos = $openid->getUserInfos($code,$state))
return function() {};
$auth = ZendAfi_Auth::getInstance();
$id = Class_User_Identity::getUserOpenId();
if ($id && ($user = Class_Users::getIdentity())) {
Class_User_Identity::findOrCreateForUserAndApplication($user,$provider,$id);
$this->redirect_url = $openid->getRedirectUrl();
}
if ($id && ($identity = Class_User_Identity::findFirstBy(['provider_id' => $provider->getId(),
'identifier' => $id]))) {
$auth->logUser($identity->getUser());
$this->redirect_url = $openid->getRedirectUrl();
}
if ($this->shouldRedirect())
$this->controller->redirect($this->redirect_url);
return $this;
}
}
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',