Utiliser Paheko avec un système de SSO (OpenID Connect ou LDAP)
Par défaut pour se connecter ce sont les comptes définis dans les fiches de membres qui sont utilisés, avec les mot de passe associés.
Cependant si Paheko est utilisé dans le contexte d'une installation utilisant d'autres outils, il peut être utile de mettre en commun l'authentification avec d'autres outils.
Une première manière de faire est d'utiliser Paheko comme source principale d'identification et authentification. Pour cela on peut utiliser ce serveur LDAP qui utilise la base de données de Paheko.
Une autre manière d'aborder la problématique est de considérer Paheko comme un simple gestionnaire de données, et ne pas utiliser le système d'authentification fourni, mais se reposer sur un SSO tiers, comme un serveur LDAP ou OpenID Connect externe par exemple.
Limitations des utilisateurs virtuels
Si on n'active pas la constante OIDC_CLIENT_MATCH_EMAIL, cela fera en sorte que l'utilisateur connecté est "virtuel" (il n'existe donc pas dans la liste des membres) et donc certaines fonctionnalités seront désactivées :
- l'utilisateur connecté ne peut pas se déconnecter, c'est à vous de gérer la déconnexion d'une autre manière
- l'utilisateur connecté ne pourra pas modifier ses informations personnelles, ni accéder à son historique d'activité
- l'utilisateur connecté ne pourra pas configurer l'authentification à deux facteurs (2FA) ni le chiffrement des mails avec PGP
- l'utilisateur ne pourra pas enregistrer de recherches enregistrées privées
- l'utilisateur (s'il a la permission) pourra supprimer les administrateurs de l'association (ou les placer dans une catégorie qui les empêche de se connecter), empêchant quiconque de gérer l'association ensuite via la connexion classique de Paheko
Il est possible de contourner ces limitations en créant l'utilisateur dans la liste des membres à la connexion, voir la constante OIDC_CLIENT_CALLBACK plus bas.
Utiliser Paheko avec un fournisseur OpenID Connect (OIDC)
Depuis la version 1.3.16, Paheko permet d'utiliser un fournisseur OIDC pour se connecter.
C'est la manière la plus simple de se connecter à un SSO existant, car la plupart des logiciels de SSO gèrent ce protocole.
Pour cela, se référer aux constantes OIDC_* dans config.dist.php.
Exemple :
const OIDC_CLIENT_URL = 'https://oidctest.wsweet.org/';
const OIDC_CLIENT_ID = 'private';
const OIDC_CLIENT_SECRET = 'tardis';
const OIDC_CLIENT_MATCH_EMAIL = false;
const OIDC_CLIENT_BUTTON = 'Se connecter avec le test OIDC';
const OIDC_CLIENT_DEFAULT_PERMISSIONS = ['users' => 'admin', 'config' => 'admin'];
Utiliser une fonction de callback après la connexion
Depuis la version 1.3.18, Paheko permet de définir une fonction de callback après la connexion OIDC, avec la constante OIDC_CLIENT_CALLBACK.
Cela permet par exemple de créer ou mettre à jour un membre Paheko à partir des infos fournies à la connexion OIDC.
Le premier paramètre passé à cette fonction sera un stdClass contenant les informations renvoyées par le serveur OIDC. Le second paramètre sera l'entité User correspond à l'utilisateur connecté. La fonction peut renvoyer une entité User visant à remplacer celle qui est utilisée actuellement, ou NULL. Si on renvoie NULL, c'est simplement l'entité User passée en paramètre qui sera l'utilisateur connecté.
Attention : si on spécifie la constante OIDC_CLIENT_MATCH_EMAIL = true, la fonction de callback ne sera appelée que si un membre avec cette adresse e-mail existe.
Voici un exemple qui définit des permissions selon le nom du groupe fourni par le serveur OIDC, et qui crée ou met à jour la fiche membre à partir des informations fournies, dans une catégorie "Membres actifs".
const OIDC_CLIENT_MATCH_EMAIL = false;
const OIDC_CLIENT_CALLBACK = '\Paheko\oidc_login_create';
use Paheko\Entities\Users\User;
use Paheko\Users\Categories;
use Paheko\Users\Users;
use stdClass;
function oidc_login_create(stdClass $infos, User $user): ?User
{
if ($infos->group === 'paheko_admins') {
// Accès membre du CA
$permissions = ['users' => 'admin', 'config' => 'admin', 'accounting' => 'admin', 'web' => 'admin', 'documents' => 'admin'];
}
elseif ($infos->group === 'paheko_compta') {
// Accès comptable
$permissions = ['accounting' => 'admin'];
}
else {
// Membre normal, ne peut que voir ses propres infos
$permissions = [];
}
$found = Users::getFromLogin($infos->email);
// Le membre existe déjà
if ($found) {
$found->setPermissions($permissions);
return $found;
}
// On cherche le numéro de la catégorie "Membres actifs"
$categories = Categories::listAssoc();
$id_category = array_search('Membres actifs', $categories, true);
if (!$id_category) {
throw new \LogicException('La catégorie n\'existe pas');
}
$user->set('id_category', $id_category);
$user->setPermissions($permissions);
$user->save();
return $user;
}
Utiliser Paheko avec un système de SSO custom (par exemple LDAP)
Depuis la version 1.3.0 il est possible de définir manuellement l'identité du membre connecté.
Pour cela il faut définir dans le fichier config.local.php la constante LOCAL_LOGIN sous forme de tableau (array) contenant les informations de l'utilisateur connecté, et les permissions.
Voici un exemple d'utilisateur connecté :
use Paheko\Users\Session;
const LOCAL_LOGIN = [
'user' => [
'_name' => 'bohwaz',
],
'permissions' => [
Session::SECTION_USERS => Session::ACCESS_ADMIN,
Session::SECTION_ACCOUNTING => Session::ACCESS_READ,
Session::SECTION_WEB => Session::ACCESS_WRITE,
Session::SECTION_CONFIG => Session::ACCESS_NONE,
Session::SECTION_DOCUMENTS => Session::ACCESS_ADMIN,
],
];
Le tableau user peut contenir n'importe quel champ de la fiche membre. La clé spéciale _name désigne le nom de l'utilisateur connecté, quel que soit le nom réel du champ "nom" de la fiche membre (les champs peuvent être renommés ou supprimés).
Pour les permissions, les valeurs acceptées sont :
Session::ACCESS_NONE |
Pas d'accès à cette partie, qui n'apparaîtra pas dans le menu |
Session::ACCESS_READ |
Accès en lecture |
Session::ACCESS_WRITE |
Accès en lecture et écriture |
Session::ACCESS_ADMIN |
Accès administrateur |
À noter que pour config, seules les valeurs NONE et ADMIN sont acceptées.
Exemple avec LDAP
Cet exemple utilise une page de connexion et vérifie les informations depuis un serveur LDAP.
const LDAP_HOST = 'localhost';
const LDAP_DN = 'cn=%s,ou=users,dc=yunohost,dc=org';
session_start();
if (empty($_SESSION['ldap_user']) && !empty($_POST['ldap_login']) && !empty($_POST['ldap_password'])) {
$l = ldap_connect(LDAP_HOST) || die('Connexion impossible');
ldap_set_option($l, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($l, LDAP_OPT_REFERRALS, 0);
ldap_set_option($l, LDAP_OPT_NETWORK_TIMEOUT, 10);
$login = trim($_POST['ldap_login']);
if (ldap_bind($l, sprintf(LDAP_DN, $login), $_POST['ldap_password'])) {
$_SESSION['ldap_user'] = $login;
}
ldap_close($l);
}
if (empty($_SESSION['ldap_user'])) {
echo '<!DOCTYPE html>
<html>
<body>
<form method="post" action="">';
if (!empty($_POST['ldap_login'])) {
echo '<p style="color: red">Identifiants invalides</p>';
}
echo '
<fieldset>
<legend>Connexion</legend>
<dl>
<dt>Login</dt>
<dd><input type="text" name="ldap_login" required /></dd>
<dt>Mot de passe</dt>
<dd><input type="password" name="ldap_password" required /></dd>
</dl>
<p><input type="submit" value="Connexion" /></p>
</fieldset>
</form>
</body>
</html>';
exit;
}
define('Paheko\LOCAL_LOGIN', [
'user' => [
'_name' => $_SESSION['ldap_user'],
],
'permissions' => [
'users' => 9,
'accounting' => 9,
'web' => 9,
'documents' => 9,
'config' => 9,
],
]);