Lerm-IT

Blog traitant de technologies informatiques. Logiciel libre, AdminSys, DevOps et GNU/Linux !

11 Dec 2010

[Symfony] Utilisation du plugin slapOrm.

SlapORM

Depuis quelque temps je recherche une méthode simple d’accéder à mes entrées LDAP via symfony. Il existe bien plusieurs solutions pour authentifier nos utilisateurs depuis l’annuaire mais quand on parle de modification ceci est une toute autre histoire ! Nous allons donc voir ici comment manipuler nos entrées LDAP à l’aide du plugin slapOrm. Il va sans dire que quelques bases de php/symfony ainsi que de l’architecture LDAP sont nécessaires à la compréhension de cet article.

slapOrm késako ?

Commençons par replacer les choses dans leurs contextes. Un annuaire LDAP est, comme son nom l’indique, un annuaire. Il stocke donc des données sous forme hiérarchique et ceci de manière optimisée pour la lecture. Le meilleur exemple pour vous schématiser ce concept est de vous imaginer l’annuaire téléphonique. Dans celui-ci les numéros de téléphone sont stockés sous forme hiérarchique (L’annuaire, contient des noms de villes qui contiennent des personnes qui possèdent un à plusieurs numéros de téléphone.) aussi il est assez simple de retrouver un numéro de téléphone à l’aide de cette hiérarchie. Le revers de la médaille est la difficulté rencontrée pour écrire dans celui-ci. Un simple rapport du temps que vous mettez à trouver un numéro de téléphone par rapport au temps que vous mettez pour apparaître dans l’annuaire vous montre clairement la limite ! Nous utiliserons dans cet article OpenLDAP comme serveur LDAP.

Un ORM pour object-relational mapping ou mapping objet-relationnel en français est une technique de programmation permettant d’accéder à des données d’une base de données relationnelle sous forme d’objet. Ici dire que nous utilisons un ORM pour accéder à notre annuaire est un abus de langage.

Ce que nous allons faire réellement est de créer une abstraction de la hiérarchie de l’annuaire pour pouvoir l’utiliser avec des objets simples. En gros nous allons spécifier que nos utilisateurs se trouvent dans tel branche de l’annuaire et nous allons avoir un objet pour pouvoir y accéder simplement.

Vous l’aurez compris c’est le plugin slapOrm qui nous permet de faire ceci. Aux vus du manque flagrant de documentations sur le projet je vais tenter d’exprimer aux mieux les différents points d’utilisation ici.

Installation

slapOrm ne bénéficie pas encore d’une validation dans les dépôts officiels des plugins de symfony aussi nous allons donc opter pour une installation manuelle! Le plus simple est de télécharger et d’extraire les sources du plugin dans le dossier “plugins” de symfony.

$ wget http://download.github.com/chanmix51-slapOrm-472ba3c.tar.gz
$ tar xvf chanmix51-slapOrm-472ba3c.tar.gz -C /path/vers/dossier/plugins/
$ mv /path/vers/dossier/plugins/chanmix51-slapOrm-472ba3c /path/vers/dossier/plugins/slapOrmPlugin

Ceci est bien entendu à adapter à la dernière version du plugin.

Une fois ceci effectué nous allons activer le plugin dans la configuration de symfony. Editer donc le fichier config/ProjectConfiguration.class.php et activer le plugin

> $ vi config/ProjectConfiguration.class.php
...
public function setup()
{
  ...
  $this->enablePlugins('slapOrmPlugin');
  ...
}
...

Vous avez maintenant installé le plugin. Vous remarquerez que deux nouvelles actions sont disponible avec la commande symfony.

slaporm
  :build-form                  Generate forms associated to the LDAP model classes
  :build-model                 Generate LDAP model classes based on the schema definition

Sans plus attendre continuons la configuration pour nous connecter au serveur LDAP.

Connexion au serveur

La connexion au serveur LDAP se fait avec le fichier de configuration de l’application (les variables de configuration app_ldap_host, app_ldap_port, app_ldap_dn et app_ldap_pass). Nous allons donc éditer notre fichier de configuration app.yml de notre application (ici frontend) et remplir le fichier avec les options correspondantes à nos besoins.

$ vi apps/frontend/config/app.yml
all:
  ldap:
    host: 127.0.0.1
    port: 389
    dn: cn=admin,ou=users,dc=exemple,dc=com
    pass: password

Création du schéma

Nous allons maintenant configurer le schéma de notre ORM. C’est ici que nous allons spécifier les emplacements de nos entrées dans l’annuaire ainsi que les classes et attributs qui lui sont liés. Il nous faut donc savoir plusieurs choses :

– Le nom que nous voulons donner à l’objet (le nom de la classe qui sera généré)

– L’emplacement dans la hiérarchie des entités et leur nomination (le dn et rdn, ex : ou=users,dc=exemple,dc=com pour le dn et cn pour le rdn)

– Les “objectClass” utilisé par l’objet (ex: inetOrgPerson, posixAccount)

– les attributs utilisés (ex: sn, cn, mail, …)

Il nous faut ensuite construire un fichier schema.yml dans le dossier config/slaporm construit de la sorte

ObjectName:
  dn: "_ou=here,dc=exemple,dc=com"
  objectClass: [objectClass1, objectClass2]
  rdn: myRdn
  attributes:
    attributes1:         { type: attributeType, param1: value, param2: value }
    attributes2:         { type: attributeType, param1: value, param2: value }
    attributes3:         { type: attributeType, param1: value, param2: value }

Le paramètre type peut contenir une valeur parmis les suivantes : dn, integer, mail ou string ceci modifiant le conportemant du plugin en ce qui concerne la génération automatique de formulaire.

Voici un exemple de fichier de configuration schema.yml

User:
  dn: "ou=users,dc=exemple,dc=com"
  objectClass: [posixAccount, inetOrgPerson]
  rdn: cn
  attributes:
    cn:         { type: string, length: 32768, multiple: false, required: true }
    gidNumber:  { type: string, length: 32768,  multiple: false, required: true }
    givenName:  { type: string, length: 32768, multiple: false }
    homeDirectory: { type: string, length: 32768, multiple: false, required: true }
    mail:  { type: mail, multiple: false }
    sn:         { type: string, length: 32768, multiple: false }
    uid:         { type: string, length: 32768, multiple: true, required: true }
    uidNumber:  { type: string, length; 32769, multiple: false, required: true }
    userPassword:         { type: string, length: 32768, multiple: false }
Group:
  dn: "ou=groups,dc=exemple,dc=com"
  objectClass: [posixGroup]
  rdn: cn
  attributes:
    cn:     { type: string, length: 32768, multiple: false, required: true }
    gidnumber: { type: string, length: 32768, multiple: false, required: true }
    userpassword: { type: string, length: 32768, multiple: false }
    memberuid: { type: string, length: 32768, multiple: true }
    description: { type: string, length: 32768, multiple: false }

Attention à bien respecter les espaces (toujours par groupe de deux).

Créer une entrée

La création d’une entrée est donc intimement lié à la création d’un objet ! Ici nous allons créer une entrée de type “User” définit plus haut. Pour cela nous créons une instance de la classe User et utilisons les fonctions magiques de type set et get pour spécifier les attributs de l’objet. Attention tout de même toutes les fonctions set et get, pour fonctionner doivent n’avoir qu’une majuscule : La première lettre du nom de l’attribut sa suite étant en minuscule. Si vous spécifier une autre majuscule elle sera automatiquement mise en minuscule et précédé par un “underscore” (_).

La sauvegarde de l’objet dans l’annuaire est quant à elle réalisé par la “classe map” de la classe entité expliqué ci-dessus. Ainsi nous pouvons sur n’importe qu’elle classe entité utiliser la fonction getMapInstance().

Puisqu’il n’y a rien de plus compréhensible qu’un peu de code

$user = new User();
$user->setCn("toto4");
$user->setGidnumber("10001");
$user->setHomedirectory("/home/toto4");
$user->setUid(array("toto"));
$user->setUidnumber("1004");
$user->setUserpassword("toto");
$user->setSn(array('toto4'));
$user->setMail(array('[email protected]'));
$user->getMapInstance()->save($user);

Attention tout de même si vous avez des attributs de type boolean (1.3.6.1.4.1.1466.115.121.1.7) vous devez spécifier TRUE ou FALSE (en majuscule).

Récupérer un ou plusieurs objets

Le plus simple pour récupérer des informations est de récupérer toutes les entités pour une classe entité donnée (Exemple: récupérer tous les utilisateurs). Pour ceci dans la classe Map il suffit d’exécuter la fonction findAll(). Exemple

$users   = SlapOrm::getMapInstanceOf('User')->findAll();
?>
There are <?php echo count($users) ?> users in this result:
<ul>
<?php foreach($users as $user): ?>
  <li><?php echo $user->getCn() ?> has mail : <?php echo $user->getMail() ?></li>
<?php endforeach ?>
</ul>

Il existe aussi la fonction getByRdn qui vous permet de rechercher une entité à l’aide de son RDN. Exemple

$user = SlapOrm::getMapInstanceOf('User')->getByRdn("lermit");

Enfin pour rechercher au plus fin il existe aussi les fonctions addAndFilter et addOrFilter qui sont détaillées dans la documentation officielle.

Références