Allow a sequence of filters in LSobjects profile configurations

It's now possible for example to define a profile on an LSobject whose
attribute would contain the DN of a group the user is member of instead
of directly the dn of the user. A possible configuation using this new feature:

  'LSprofile' => array(
    'admin' => array(
      'LSobjects' => array(
        'LSsupannGroupAdminByGroup' => array(
          'filters' => array(
            array(
              'basedn' => $basedn,
              'attr' => 'member',
              'attr_value' => '%{dn}',
              'LSobject' => 'LSsupannGroup',
            ),
            array(
              'basedn' => $basedn,
              'attr' => 'supannGroupeAdminDN',
              'attr_value' => '%{dn}',
              'LSobject' => 'LSsupannGroup',
            )
          ),
        ),
      ),
    ),
  )

Signed-off-by: Benjamin Renard <brenard@easter-eggs.com>
This commit is contained in:
Benjamin Dauvergne 2014-12-13 12:15:37 +01:00 committed by Benjamin Renard
parent 10019fc9fe
commit 9add9c3321
2 changed files with 166 additions and 38 deletions

View file

@ -35,6 +35,20 @@
'basedn' => [basedn de recherche],
'params' => [configuration de la recherche]
),
[nom quelconque] => array (
'filters' => array(
array(
'LSobject' => [nom du LSobject],
'attr' => [nom de l'attribut clé],
'attr_value' => [format de la valeur de l'attribut clé],
// ou
'filter' => [format du filtre de recherche],
'basedn' => [basedn de recherche],
'params' => [configuration de la recherche]
),
),
),
...
)
),
@ -151,6 +165,20 @@ objets pour lesquels l'utilisateur appartiendra au
'basedn' => [basedn de recherche],
'params' => [configuration de la recherche]
),
array (
'filters' => array(
array(
'LSobject' => [nom du LSobject],
'attr' => [nom de l'attribut clé],
'attr_value' => [format de la valeur de l'attribut clé],
// ou
'filter' => [format du filtre de recherche],
'basedn' => [basedn de recherche],
'params' => [configuration de la recherche]
),
),
),
...
)
),
@ -159,18 +187,43 @@ objets pour lesquels l'utilisateur appartiendra au
...
</programlisting>
<para>Explications&nbsp;: Dans la configuration d'un <emphasis>LSprofile</emphasis>,
la valeur clé <emphasis>LSprofile</emphasis> signifie qu'on est dans un cas de la
délégation de droits sur des types d'LSobject. Dans ce tableau associatif, il
la valeur clé <emphasis>LSobjects</emphasis> signifie qu'on est dans un cas de la
délégation de droits sur des types d'LSobject. Dans ce tableau associatif, il
est possible de définir un ou plusieurs types de LSobject pour lesquels on délègue
des droits. Dans ce tableau la valeur clé est le nom du LSobject et la valeur
associée est un tableau contenant la configuration permettant de dire quels sont
les LSobjets de ce type concernés par la délégation.</para>
<para>Cette configuration contient les paramètres d'une recherche dans l'annuaire
des droits via des recherches simples ou enchaînées. Le fonctionnement simple
consiste à partir de l'objet de l'utilisateur et à générer un filtre de
recherche sur un type de LSobject. Le fonctionnement enchainée consiste à faire
un première recherche à partir de l'objet de l'utilisateur puis à recommencer à
partir des objets trouvés en construisant une liste de filtres de recherche
pour chaque objet qui seront combinés via l'opérateur booléen
<emphasis>ou</emphasis>.</para>
<para>Pour configurer une délégation de type simple on mettra le nom du
LSobject dans la clé du tableau et dans la valeur un tableau définissant la
recherche. Il est possible de ne pas utiliser la clé du tableau comme nom du
LSobject grâce à la clé de configuration
<emphasis>LSobject</emphasis>.</para>
<para>Pour configurer une délégation de type enchaîné on pourra utiliser
n'importe quelle valeur unique pour la clé du tableau et pour la valeur un
tableau contenant une unique clé <emphasis>filters</emphasis>. La valeur
associée à cette clé est celle d'une délégation de type simple où la clé
<emphasis>LSobject</emphasis> est devenue obligatoire.</para>
<para>Cette configuration contient les paramètres d'une ou plusieurs recherches dans l'annuaire
en considérant que l'utilisateur connecté aura les droits du LSprofile sur les
objets retournés. Les paramètres de la recherche sont&nbsp;:
<variablelist>
<varlistentry>
<term>LSobject</term>
<listitem>
<simpara>C'est le nom du LSobject recherché.
<emphasis>(Paramètre facultatif pour une délégation de type simple)</emphasis></simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>attr</term>
<listitem>

View file

@ -1484,6 +1484,111 @@ class LSsession {
return LStemplate :: fetch($template);
}
/**
* Prend un tableau de LSobject et le réduit en utilisant un filtre de
* recherche sur un autre type de LSobject.
*
* Si une erreur est présente dans le tableau de définition du filtre, un
* tableau vide est renvoyé.
*
* @param[in] string $LSobject le type LSobject par défaut
* @param[in] array $set tableau de LSobject
* @param[in] array $filter_def définition du filtre de recherche pour la réduction
* @param[in] string $basend basedn pour la recherche, null par défaut
*
* @retval array le nouveau tableau de LSobject
*/
private static function reduceLdapSet($LSobject, $set, $filter_def, $basedn=null) {
if (empty($set)) {
return array();
}
if (! isset($filter_def['filter']) &&
(! isset($filter_def['attr']) ||
! isset($filter_def['attr_value']))) {
LSdebug("Filtre de profil LSobject invalide " . var_export($filter_def, true));
return array();
}
LSdebug('LSsession :: reducing set of');
foreach ($set as $object) {
LSdebug('LSsession :: -> ' . $object -> getDn());
}
$LSobject = isset($filter_def['LSObject']) ? $filter_def['LSobject'] : $LSobject;
LSdebug('LSobject :: ' . $LSobject);
$filters = array();
foreach ($set as $object) {
if (isset($filter_def['filter'])) {
$filters[] = $object -> getFData($filter_def['filter']);
}
else {
$value = $object -> getFData($filter_def['attr_value']);
$filters[] = Net_LDAP2_Filter::create($filter_def['attr'], 'equals', $value);
}
}
$filter = LSldap::combineFilters('or', $filters);
$params = array(
'basedn' => isset($filter_def['basedn']) ? $filter_def['basedn'] : $basedn,
'filter' => $filter,
);
if (isset($filter_def['params']) && is_array($filter_def['params'])) {
$params = array_merge($filter_def['params'],$params);
}
$LSsearch = new LSsearch($LSobject,'LSsession :: loadLSprofiles',$params,true);
$LSsearch -> run(false);
$set = $LSsearch -> listObjects();
LSdebug('LSsession :: reduced set to');
foreach ($set as $object) {
LSdebug('LSsession :: -> ' . $object -> getDn());
}
return $set;
}
/**
* Charge les droits LS de l'utilisateur : uniquement du type LSobjects
*
* @param[in] string $
*
* @retval void
*/
private static function loadLSprofilesLSobjects($profile, $LSobject, $listInfos) {
if (! self :: loadLSclass('LSsearch')) {
LSdebug('Impossible de charger la classe LSsearch');
return;
}
# we are gonna grow a set of objects progressively, we start from the user
$set = array(self :: getLSuserObject());
$basedn = isset($listInfos['basedn']) ? $listInfos['basedn'] : null;
$LSobject = isset($listInfos['LSobject']) ? $listInfos['LSobject'] : $LSobject;
if (isset($listInfos['filters']) && is_array($listInfos['filters'])) {
foreach ($listInfos['filters'] as $filter_def) {
$set = self :: reduceLdapSet($LSobject, $set, $filter_def, $basedn);
}
}
if (isset($listInfos['filter']) || (isset($listInfos['attr']) && isset($listInfos['attr_value']))) {
# support legacy profile definition
$set = self :: reduceLdapSet($LSobject, $set, $listInfos, $basedn);
}
$DNs = [];
foreach ($set as $object) {
$DNs[] = $object -> getDn();
}
if (!is_array(self :: $LSprofiles[$profile])) {
self :: $LSprofiles[$profile]=$DNs;
}
else {
foreach($DNs as $dn) {
if (!in_array($dn,self :: $LSprofiles[$profile])) {
self :: $LSprofiles[$profile][] = $dn;
}
}
}
}
/**
* Charge les droits LS de l'utilisateur
*
@ -1501,38 +1606,8 @@ class LSsession {
if ($topDn == 'LSobjects') {
if (is_array($rightsInfos)) {
foreach ($rightsInfos as $LSobject => $listInfos) {
if (self :: loadLSclass('LSsearch')) {
if (isset($listInfos['filter'])) {
$filter = self :: getLSuserObject() -> getFData($listInfos['filter']);
}
else {
$filter = '('.$listInfos['attr'].'='.self :: getLSuserObject() -> getFData($listInfos['attr_value']).')';
}
$params = array (
'basedn' => (isset($listInfos['basedn'])?$listInfos['basedn']:null),
'filter' => $filter
);
if (isset($listInfos['params']) && is_array($listInfos['params'])) {
$params = array_merge($listInfos['params'],$params);
}
$LSsearch = new LSsearch($LSobject,'LSsession :: loadLSprofiles',$params,true);
$LSsearch -> run(false);
$DNs = $LSsearch -> listObjectsDn();
if (!is_array(self :: $LSprofiles[$profile])) {
self :: $LSprofiles[$profile]=$DNs;
}
else {
foreach($DNs as $dn) {
if (!in_array($dn,self :: $LSprofiles[$profile])) {
self :: $LSprofiles[$profile][] = $dn;
}
}
}
}
LSdebug('loading LSprofile ' . $profile . ' for LSobject ' . $LSobject . ' with params ' . var_export($listInfos, true));
self :: loadLSprofilesLSobjects($profile, $LSobject, $listInfos);
}
}
else {