diff --git a/modules/multiauth/default-enable b/modules/multiauth/default-enable new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/modules/multiauth/dictionaries/multiauth.php b/modules/multiauth/dictionaries/multiauth.php new file mode 100644 index 0000000000000000000000000000000000000000..b398cec7d2a32fc58dac665b5e8ea660ac1d47ec --- /dev/null +++ b/modules/multiauth/dictionaries/multiauth.php @@ -0,0 +1,13 @@ +<?php + +$lang = array( + 'select_source_header' => array( + 'en' => 'Select an authentication source', + 'es' => 'Seleccione una fuente de autenticación', + ), + 'select_source_text' => array( + 'en' => 'The selected authentication source will be used to authenticate you and and to create a valid session.', + 'es' => 'La fuente de autenticación seleccionada se utilizará para autenticarle y crear una sesión válida.', + ), + ); +?> diff --git a/modules/multiauth/docs/multiauth.txt b/modules/multiauth/docs/multiauth.txt new file mode 100644 index 0000000000000000000000000000000000000000..070ea88082b61dcb310240de663dff3d7ee3a899 --- /dev/null +++ b/modules/multiauth/docs/multiauth.txt @@ -0,0 +1,54 @@ +MultiAuth module +================ + +The MultiAuth module provides a method for authenticating users agains +a list of authentication sources. There is only one authentication +module: + +`multiauth:MultiAuth` +: Authenticate the user against a list of authentication sources. + + +`multiauth:MultiAuth` +--------------------- + +This module is useful when you want to let the users decide which +authentication source fits better their needs at any scenario. For +example, they can choose the `saml` authentication source in most +cases and then switch to the `admin` authentication source when +'saml' is down for some reason. + +To create a MultiAuth authentication source, open +`config/authsources.php` in a text editor, and add an entry for the +authentication source: + + 'example-multi' => array( + 'multiauth:MultiAuth', + + /* + * The available authentication sources. + * They must be defined in this authsources.php file. + */ + 'sources' => array('example-saml', 'example-admin'), + ), + + 'example-saml' => array( + 'saml:SP', + 'entityId' => 'my-entity-id', + 'idp' => 'my-idp', + ), + + 'example-admin' => array( + 'core:AdminPassword', + ), + +You should update the name of this authentication source +(`example-multi`), and the authentication sources it references, +to have a name which makes sense to your organization. + +The MultiAuth authentication sources only has an option: the +`sources` option, and it is required. It is an array of other +authentication sources defined in the `config/authsources.php` +file. The order in this array does not matter since the user +is the one that decides which one to use. + diff --git a/modules/multiauth/lib/Auth/Source/MultiAuth.php b/modules/multiauth/lib/Auth/Source/MultiAuth.php new file mode 100644 index 0000000000000000000000000000000000000000..6bf557235f00390fdf1f746c126b7f3d13f39c34 --- /dev/null +++ b/modules/multiauth/lib/Auth/Source/MultiAuth.php @@ -0,0 +1,151 @@ +<?php + +/** + * Authentication source which let the user chooses among a list of + * other authentication sources + * + * @author Lorenzo Gil, Yaco Sistemas S.L. + * @package simpleSAMLphp + * @version $Id$ + */ + +class sspmod_multiauth_Auth_Source_MultiAuth extends SimpleSAML_Auth_Source { + + /** + * The key of the AuthId field in the state. + */ + const AUTHID = 'sspmod_multiauth_Auth_Source_MultiAuth.AuthId'; + + /** + * The string used to identify our states. + */ + const STAGEID = 'sspmod_multiauth_Auth_Source_MultiAuth.StageId'; + + /** + * The key where the sources is saved in the state. + */ + const SOURCESID = 'sspmod_multiauth_Auth_Source_MultiAuth.SourceId'; + + /** + * The key where the selected source is saved in the session. + */ + const SESSION_SOURCE = 'multiauth:selectedSource'; + + /** + * Array of sources we let the user chooses among. + */ + private $sources; + + /** + * Constructor for this authentication source. + * + * @param array $info Information about this authentication source. + * @param array $config Configuration. + */ + public function __construct($info, $config) { + assert('is_array($info)'); + assert('is_array($config)'); + + /* Call the parent constructor first, as required by the interface. */ + parent::__construct($info, $config); + + if (!array_key_exists('sources', $config)) { + throw new Exception('The required "sources" config option was not found'); + } + + $this->sources = $config['sources']; + } + + /** + * Prompt the user with a list of authentication sources. + * + * This method saves the information about the configured sources, + * and redirects to a page where the user must select one of these + * authentication sources. + * + * This method never return. The authentication process is finished + * in the delegateAuthentication method. + * + * @param array &$state Information about the current authentication. + */ + public function authenticate(&$state) { + assert('is_array($state)'); + + $state[self::AUTHID] = $this->authId; + $state[self::SOURCESID] = $this->sources; + + /* Save the $state array, so that we can restore if after a redirect */ + $id = SimpleSAML_Auth_State::saveState($state, self::STAGEID); + + /* Redirect to the select source page. We include the identifier of the + saved state array as a parameter to the login form */ + $url = SimpleSAML_Module::getModuleURL('multiauth/selectsource.php'); + $params = array('AuthState' => $id); + SimpleSAML_Utilities::redirect($url, $params); + + /* The previous function never returns, so this code is never + executed */ + assert('FALSE'); + } + + /** + * Delegate authentication. + * + * This method is called once the user has choosen one authentication + * source. It saves the selected authentication source in the session + * to be able to logout properly. Then it calls the authenticate method + * on such selected authentication source. + * + * @param string $authId Selected authentication source + * @param array $state Information about the current authentication. + */ + public static function delegateAuthentication($authId, $state) { + assert('is_string($authId)'); + assert('is_array($state)'); + + $as = SimpleSAML_Auth_Source::getById($authId); + if ($as === NULL) { + throw new Exception('Invalid authentication source: ' . $authId); + } + + /* Save the selected authentication source for the logout process. */ + $session = SimpleSAML_Session::getInstance(); + $session->setData(self::SESSION_SOURCE, $state[self::AUTHID], $authId); + + try { + $as->authenticate($state); + } catch (SimpleSAML_Error_Exception $e) { + SimpleSAML_Auth_State::throwException($state, $e); + } catch (Exception $e) { + $e = new SimpleSAML_Error_UnserializableException($e); + SimpleSAML_Auth_State::throwException($state, $e); + } + self::loginCompleted($state); + } + + /** + * Log out from this authentication source. + * + * This method retrieves the authentication source used for this + * session and then call the logout method on it. + * + * @param array &$state Information about the current logout operation. + */ + public function logout(&$state) { + assert('is_array($state)'); + + /* Get the source that was used to authenticate */ + $session = SimpleSAML_Session::getInstance(); + $authId = $session->getData(self::SESSION_SOURCE, $this->authId); + + $source = SimpleSAML_Auth_Source::getById($authId); + if ($source === NULL) { + throw new Exception('Invalid authentication source during logout: ' . $source); + } + /* Then, do the logout on it */ + $source->logout($state); + } + +} + +?> \ No newline at end of file diff --git a/modules/multiauth/templates/selectsource.php b/modules/multiauth/templates/selectsource.php new file mode 100644 index 0000000000000000000000000000000000000000..6cf7fa03105d8a013f87f53ecf5e24c0a7455ffc --- /dev/null +++ b/modules/multiauth/templates/selectsource.php @@ -0,0 +1,22 @@ +<?php +$this->data['icon'] = 'lock.png'; +$this->data['header'] = $this->t('{multiauth:multiauth:select_source_header}'); + +$this->includeAtTemplateBase('includes/header.php'); +?> + +<h2><?php echo $this->t('{multiauth:multiauth:select_source_header}'); ?></h2> + +<p><?php echo $this->t('{multiauth:multiauth:select_source_text}'); ?></p> + +<ul> +<?php +foreach($this->data['sources'] as $source) { + echo '<li><a href="?source=' . htmlspecialchars($source) . + '&AuthState=' . htmlspecialchars($this->data['authstate']) . '">' . + htmlspecialchars($source) . '</a></li>'; +} +?> +</ul> + +<?php $this->includeAtTemplateBase('includes/footer.php'); ?> diff --git a/modules/multiauth/www/selectsource.php b/modules/multiauth/www/selectsource.php new file mode 100644 index 0000000000000000000000000000000000000000..41f0c73b3cf02c61b77534cb6065c29c2d14e773 --- /dev/null +++ b/modules/multiauth/www/selectsource.php @@ -0,0 +1,34 @@ +<?php + +/** + * This page shows a list of authentication sources. When the user selects + * one of them if pass this information to the + * sspmod_multiauth_Auth_Source_MultiAuth class and call the + * delegateAuthentication method on it. + * + * @author Lorenzo Gil, Yaco Sistemas S.L. + * @package simpleSAMLphp + * @version $Id$ + */ + +if (!array_key_exists('AuthState', $_REQUEST)) { + throw new SimpleSAML_Error_BadRequest('Missing AuthState parameter.'); +} +$authStateId = $_REQUEST['AuthState']; + +/* Retrieve the authentication state. */ +$state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_multiauth_Auth_Source_MultiAuth::STAGEID); + +if (array_key_exists('source', $_REQUEST)) { + $source = $_REQUEST['source']; + sspmod_multiauth_Auth_Source_MultiAuth::delegateAuthentication($source, $state); +} + +$globalConfig = SimpleSAML_Configuration::getInstance(); +$t = new SimpleSAML_XHTML_Template($globalConfig, 'multiauth:selectsource.php'); +$t->data['authstate'] = $authStateId; +$t->data['sources'] = $state[sspmod_multiauth_Auth_Source_MultiAuth::SOURCESID]; +$t->show(); +exit(); + +?> \ No newline at end of file