Uubu.org

Systèmes d'information: une approche OpenSource

  

OpenLDAP - Personalisation du schéma

Création d'un schéma personnalisé

Le 16 juin 2014 , Aucun commentaire pour cet article


Dans cet article, nous allons créer un schéma personnalisé. Nous utiliserons l'héritage pour simplifier le schéma, via le biais de définitions génériques. Le scénario utilisé permet de comprendre les différents composants et leurs intéractions, tout en se conformant aux best practices avec cependant quelques entorses, à des fins pédagogiques.

Nous allons partir d'un exemple simple: Une entreprise de fabrique de jouets possède 3 ateliers de fabrication, chacun fabricant des jouets différents (peluches, jouets en bois, etc.). Nous souhaitons référencer les produits fabriqués, les matières premières utilisées et les fournisseurs. Ce que nous souhaitons définir, ce sont les ateliers avec le(s) responsable(s) de production, les produits, avec pour chacun, les quantités en stock, les seuil minimum et maximum de stock, la/les couleurs du jouet, le prix unitaire. Les matières première permettent de référencer les matériaux, avec les stock disponible et les founisseurs, incluant les délai de livraison et les contacts.

Nous utiliserons l'héritage pour simplifier le schéma, via le biais de définitions génériques. Nous ajouterons également un peu de contraintes à ce schéma. Commençons par notre en-tête:

dn: cn=custom,cn=schema,cn=config
ObjectClass: top
ObjectClass: olcConfig
ObjectClass: olcSchemaConfig
cn: custom

Nous utiliserons la branche expérimentale pour nos OID. Définissons quelques alias pour rendre la suite plus compréhensible:

olcObjectIdentifier: CustomRoot 1.3.6.1.3
olcObjectIdentifier: Custom CustomRoot:1
olcObjectIdentifier: CustomAttributeType CustomRoot:1
olcObjectIdentifier: CustomObjectClass CustomRoot:2
olcObjectIdentifier: CustomAttributeTypeGen CustomAttributeType:1
olcObjectIdentifier: CustomAttributeTypeDef CustomAttributeType:2
olcObjectIdentifier: CustomObjectClassGen CustomObjectClass:1
olcObjectIdentifier: CustomObjectClassDef CustomObjectClass:2

On créé des définitions génériques:

olcAttributeTypes: ( CustomAttributeTypeGen:1 NAME 'custom-DNGeneric' DESC 'Generic DN based attributes' EQUALITY distinguishedNameMatch SYNTAX OMsDN)
olcAttributeTypes: ( CustomAttributeTypeGen:2 NAME 'custom-ia5Generic' DESC 'Generic IA5 String' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX OMsIA5String)
olcAttributeTypes: ( CustomAttributeTypeGen:3 NAME 'custom-utf8Generic' DESC 'Generic Directory String' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch ORDERING caseIgnoreOrderingMatch SYNTAX OMsDirectoryString)
olcAttributeTypes: ( CustomAttributeTypeGen:4 NAME 'custom-BoolGeneric' DESC 'Generic Boolean attribute' EQUALITY booleanMatch SYNTAX OMsBoolean SINGLE-VALUE)
olcAttributeTypes: ( CustomAttributeTypeGen:5 NAME 'custom-numGeneric' DESC 'Generic numeric attribute' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX OMsInteger{16} )
olcObjectClasses: ( CustomObjectClassGen:1 NAME 'custom-StructuralGeneric' SUP custom-top DESC 'Generic structural object' STRUCTURAL MAY ( displayName $ description )

et enfin nos définitions, on commence par définir notre classe abstraite:

olcObjectClasses: ( CustomObjectClassDef:1 NAME 'custom-top' DESC 'top of our custom superclass chain' ABSTRACT MUST objectClass MAY ( description $ custom-comment ) )

Les définitions d'attributs:

olcAttributeTypes: ( CustomAttributeTypeDef:1 NAME 'custom-RefId' DESC 'Reference Identifier' SUP custom-numGeneric SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:2 NAME 'custom-comment' DESC 'Any comment about this object' SUP custom-utf8Generic )
olcAttributeTypes: ( CustomAttributeTypeDef:3 NAME 'custom-color' DESC 'toy s color' SUP custom-numGeneric )
olcAttributeTypes: ( CustomAttributeTypeDef:4 NAME 'custom-stock' DESC 'number in stock' SUP custom-numGeneric SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:5 NAME 'custom-stockMax' DESC 'Unit max in stock' SUP custom-numGeneric SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:6 NAME 'custom-stockMin' DESC 'Unit min in stock' SUP custom-numGeneric SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:7 NAME 'custom-age' DESC 'age of use' SUP custom-ia5Generic )
olcAttributeTypes: ( CustomAttributeTypeDef:8 NAME 'custom-Unit' DESC 'Unit basis' SUP custom-utf8Generic SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:9 NAME 'custom-Delay' DESC 'procurement lead time' SUP custom-utf8Generic SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:10 NAME 'custom-ppu' DESC 'Price per Unit' SUP custom-numGeneric SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:11 NAME 'custom-availability' DESC 'Availability of the reference' SUP custom-BoolGeneric )
olcAttributeTypes: ( CustomAttributeTypeDef:12 NAME 'custom-foreman' DESC 'chief workshop' SUP custom-DNGeneric SINGLE-VALUE )
olcAttributeTypes: ( CustomAttributeTypeDef:13 NAME 'custom-contact' DESC 'Supplier contact' SUP custom-utf8Generic )

 

les définitions de classes d'objet:

olcObjectClasses: ( CustomObjectClassDef:1 NAME 'custom-top' DESC 'top of our custom superclass chain' ABSTRACT MUST objectClass MAY ( description $ custom-comment ) )
olcObjectClasses: ( CustomObjectClassGen:1 NAME 'custom-StructuralGeneric' SUP custom-top DESC 'Generic structural object' STRUCTURAL MAY ( displayName $ description ) )
olcObjectClasses: ( CustomObjectClassDef:2 NAME 'custom-RefObj' DESC 'Enforce a reference' SUP custom-StructuralGeneric MUST custom-RefId )
olcObjectClasses: ( CustomObjectClassDef:3 NAME 'custom-Product' DESC 'Product définition' SUP custom-RefObj MUST custom-availability )
olcObjectClasses: ( CustomObjectClassDef:4 NAME 'custom-RawMaterials' SUP custom-RefObj )
olcObjectClasses: ( CustomObjectClassDef:5 NAME 'custom-Workshop' SUP custom-StructuralGeneric MUST custom-foreman )
olcObjectClasses: ( CustomObjectClassDef:6 NAME 'custom-Supplier' SUP custom-StructuralGeneric MUST custom-contact)
olcObjectClasses: ( CustomObjectClassDef:7 NAME 'custom-SecondaryData' SUP custom-top AUXILIARY MAY ( custom-color $ custom-stock $ custom-stockMax $ custom-stockMin $ custom-age $ custom-Unit $ custom-Delay $ custom-ppu ) )

 

Voilà pour la définition des objects. Maintenant il nous faut un peu de contraintes. Ajoutons quelques règles de contenu:

olcDitContentRules: ( CustomObjectClassDef:3 NAME 'dcr-Product' DESC 'custom-Product may only be members of the custom-SecondaryData aux class' AUX 1.3.6.1.3.1.2.2.7 NOT ( 1.3.6.1.3.1.1.2.9 $ 1.3.6.1.3.1.1.2.10) )
olcDitContentRules: ( CustomObjectClassDef:4 NAME 'dcr-RawMaterials' DESC 'custom-RawMaterials may only be members of the custom-SecondaryData aux class' AUX 1.3.6.1.3.1.2.2.7 MUST 1.3.6.1.3.1.1.2.4 MAY ( 1.3.6.1.3.1.1.2.9 $ 1.3.6.1.3.1.1.2.5 $ 1.3.6.1.3.1.1.2.6 ) NOT 1.3.6.1.3.1.1.2.8 )
olcDitContentRules: ( CustomObjectClassDef:5 NAME 'dcr-Workshop' DESC 'custom-Workshop may only be members of the custom-SecondaryData aux class' AUX 1.3.6.1.3.1.2.2.7 MUST 1.3.6.1.3.1.1.2.9 NOT ( 1.3.6.1.3.1.1.2.3 $ 1.3.6.1.3.1.1.2.4 $ 1.3.6.1.3.1.1.2.5 $ 1.3.6.1.3.1.1.2.6 $ 1.3.6.1.3.1.1.2.7 $ 1.3.6.1.3.1.1.2.8 ) )
olcDitContentRules: ( CustomObjectClassDef:6 NAME 'dcr-Supplier' DESC 'custom-Supplier may only be members of the custom-SecondaryData aux class' AUX 1.3.6.1.3.1.2.2.7 MAY 1.3.6.1.3.1.1.2.9 NOT ( 1.3.6.1.3.1.1.2.3 $ 1.3.6.1.3.1.1.2.4 $ 1.3.6.1.3.1.1.2.5 $ 1.3.6.1.3.1.1.2.6 $ 1.3.6.1.3.1.1.2.7 $ 1.3.6.1.3.1.1.2.8 ) )

 

OpenLdap ne gère pas les règles de structure, mais permet de les gérer similairement via les ACL étendues (pensez à ajouter olcAddContentAcl à votre base):

Pour cela, définissons l'arborescence suivance:

dc=uuub,dc=fr

  \_ o=Enterprise

      \_ cn=<workshop>

          \_ cn=<product>

Ce que nous souhaitons, c'est que chaque atelier soit géré par son responsable, et que ce dernier puisse créer et gérer les jouets qui y sont fabriqués, sous cet atelier.

olcAccess: to dn.baseobject="o=Enterprise,dc=uubu,dc=fr" attrs="children" by group/groupOfMembers/member="cn=Admins,dc=uubu,dc=fr" write by users read by * none break
olcAccess: to dn.onelevel="o=Enterprise,dc=uubu,dc=fr" filter="(objectClass=custom-Workshop)" attrs="entry,@custom-Workshop,@custom-SecondaryData" by group/groupOfMembers/member="cn=Admins,dc=uubu,dc=fr" write by users read by * none break

olcAccess: to dn.regex="^(cn=[^,]+),o=Enterprise,dc=uubu,dc=fr$" filter="(objectClass=custom-Workshop)" attrs=entry,@custom-Workshop,@custom-SecondaryData by set="this/custom-foreman & user" write by users read by * none break
olcAccess: to dn.regex="^(cn=[^,]+),o=Enterprise,dc=uubu,dc=fr$" filter="(objectClass=custom-Workshop)" attrs="children" by set="this/custom-foreman & user" write by * read break
olcAccess: to dn.regex="^cn=([^,]+),(cn=[^,]+,o=Enterprise,dc=uubu,dc=fr)$" filter="(objectClass=custom-Product)" attrs="entry,@custom-Product,@custom-SecondaryData" by group/custom-Workshop/custom-foreman.expand="$2" write by users read by * none

 

Attention à l'utilisation des expressions régulières gourmandes en ressources, et les sets encore considérés comme expérimentaux. Je vais m'arrêter là, les autres règles de structure sont calqués sur celles-ci et ne devraient pas poser de problème.

Comme vous pouvez le remarquer, les règles de structure sont beaucoup plus souple que les acl, mais sont moins précises. Ainsi, là où une règle de structure est définis pour tout le DIT, des acls différentes peuvent être définis pour différentes sous-arborescence. Autre avantage des acls: on gère également les droits dans la foulée, mais ce n'est pas sans une complexité accrue.

Voilà, pour cette article. Je vais consacrer un article dédié aux ACLs et à la délégation.

 

Aucun commentaire pour cet article

Note: Les commentaires sont temporaiment désactivés, merci de contacter l'auteur par mail