opendj https://www.vincentliefooghe.net/index.php/ fr Pass-Through Authentication et migration des mots de passe https://www.vincentliefooghe.net/index.php/content/pass-through-authentication-et-migration-des-mots-passe <span class="field field--name-title field--type-string field--label-hidden">Pass-Through Authentication et migration des mots de passe</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Contexte</h2> <p>Dans un projet de migration d'un annuaire AD LDS vers un Forgerock DS, le principal problème est de pouvoir récupérer les mots de passe.</p> <p>En effet, AD LDS (et AD DS) ne permettent pas d'exporter le hash du mot de passe en LDIF, et il n'est pas possible non plus <em>simplement</em> de les récupérer, même en passant par des outils tels que <em>creddump</em> , <em>ntdsextract</em> ou autre.</p> <p>Du coup, l'idée peut être intéressante de paramétrer l'annuaire Forgerock DS en mode <em>pass through authentication</em>, d'activer le cache, et ensuite d'utiliser le mot de passe local, une fois la première authentification correcte réalisée sur l'AD LDS (ou n'importe quel annuaire).</p> <h2>Pré-requis : import du certificat</h2> <p>Dans un premier temps, il faut importer le certificat de l'annuaire d'authentification. On peut récupérer le certificat avec une commande <em>openssl</em> :</p> <pre> <code>openssl s_client -connect authserver:2636 </code></pre><p>Une fois le certificat sauvegardé, on va l'intégrer avec <em>keytool</em> :</p> <pre> <code>keytool -importcert -alias authserver -keystore /opt/opendj/config/keystore -file ~/authserver.pem </code></pre><h2>Création d'un "fournisseur de confiance"</h2> <p>Via la commande <em>dsconfig</em>, on va déclarer le serveur d'authentification distant comme "<em>fournisseur de confiance</em>"</p> <pre> <code>dsconfig \ create-trust-manager-provider \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --provider-name AuthServerPKCS12 \ --type file-based \ --set enabled:true \ --set trust-store-type:PKCS12 \ --set trust-store-file:config/keystore \ --set trust-store-pin:"&amp;{file:config/keystore.pin}" \ --usePkcs12TrustStore /opt/opendj/config/keystore \ --trustStorePassword:file /opt/opendj/config/keystore.pin \ --no-prompt </code></pre><h2>Paramétrage du mode PTA</h2> <p>Il faut ensuite créer une politique d'authentification</p> <pre> <code>dsconfig \ create-password-policy \ --hostname localhost \ --port 4444 \ --bindDN uid=admin \ --bindPassword password \ --policy-name "AuthServer_PTA_Policy" \ --type ldap-pass-through \ --set primary-remote-ldap-server:authserver:636 \ --set mapped-attribute:uid \ --set mapped-search-base-dn:"cn=Users,dc=example,dc=com" \ --set mapped-search-bind-dn:"uid=ad-bind-account,cn=admins,dc=example,dc=com" \ --set mapped-search-bind-password:ZmQ5OWUw-ADpassword \ --set trust-manager-provider:AuthServerPKCS12 \ --set mapping-policy:mapped-search \ --set use-password-caching:true \ --set cached-password-storage-scheme:PBKDF2-HMAC-SHA256 \ --set cache-password-ttl:24h \ --set use-ssl:true \ --usePkcs12TrustStore /opt/opendj/config/keystore \ --trustStorePassword:file /opt/opendj/config/keystore.pin \ --no-prompt </code></pre><p>On précise notamment :</p> <ul><li>le <em>hostname</em> et le port du serveur d'authentification (dans notre exemple, <strong>authserver</strong>, qui écoute sur le port <strong>636</strong>)</li> <li>la base de recherche pour les utilisateurs</li> <li>l'attribut commun entre le compte local et le compte sur le serveur d'authentification, dans l'exemple on utilise <strong>uid</strong> (il faut donc que l'attribut soit bien unique et identique sur les 2 serveurs)</li> <li>le DN du compte sur le serveur distant</li> <li>le mot de passe du compte distant</li> <li>Le trust manager (déclaré ci-avant)</li> </ul><p>En optionnel, on active le "<em>password caching</em>", qui permet, lors d'une première authentification réalisée avec succès, de cacher le mot de passe en local pour éviter les multiples accès sur le serveur d'authentification distant. Pour ceci, il faut également définir le schéma de stockage du mot de passe caché.</p> <p>On positionne la valeur du cache (TTL) à 24 heures.</p> <h2>Assignation de la password policy à un utilisateur</h2> <p>Pour que la politique de type "<em>pass through</em>" soit appliquée à l'utilisateur, il faut l'assigner de manière explicite, par exemple via un fichier ldif :</p> <pre> <code>dn: cn=user1,ou=Externes,ou=People,dc=example,dc=com changetype: modify add: ds-pwp-password-policy-dn ds-pwp-password-policy-dn: cn=AuthServer_PTA_Policy,cn=Password Policies,cn=config </code></pre><p>Si l'utilisateur tente ensuite de se connecter au serveur DS, on peut voir les logs sur le serveur d'authentification (ici il s'agit des logs d'une autre instance Forgerock DS, utilisée pour les tests):</p> <pre> <code>{"eventName":"DJ-LDAP","client":{"ip":"127.0.0.1","port":60984},"server":{"ip":"127.0.0.1","port":2636},"request":{"protocol":"LDAPS","operation":"SEARCH","connId":8,"msgId":9,"dn":"cn=Users,dc=example,dc=com","scope":"sub","filter":"(uid=1189670333702hawl)","attrs":["1.1"]},"transactionId":"0a31b37e-b7f3-4854-9154-5ebad695ff24-488","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":1,"elapsedTimeUnits":"MILLISECONDS","nentries":1},"userId":"uid=ad-bind-account,ou=admins,dc=example,dc=com","timestamp":"2022-04-04T14:15:36.803Z","_id":"0a31b37e-b7f3-4854-9154-5ebad695ff24-490"} {"eventName":"DJ-LDAP","client":{"ip":"127.0.0.1","port":60986},"server":{"ip":"127.0.0.1","port":2636},"request":{"protocol":"LDAPS","operation":"BIND","connId":9,"msgId":8,"version":"3","dn":"cn=user1,cn=Users,dc=example,dc=com","authType":"SIMPLE"},"transactionId":"0a31b37e-b7f3-4854-9154-5ebad695ff24-491","response":{"status":"SUCCESSFUL","statusCode":"0","elapsedTime":1,"elapsedTimeUnits":"MILLISECONDS","additionalItems":{"ssf":"256"}},"userId":"cn=user1,cn=Users,dc=example,dc=com","timestamp":"2022-04-04T14:15:36.805Z","_id":"0a31b37e-b7f3-4854-9154-5ebad695ff24-493"} </code></pre><p>Si on a activé le cache, on peut constater qu'après une première authentification correcte, l'annuaire distant n'est plus sollicité lors des authentifications suivantes, sauf si le mot de passe ne correspond plus à la valeur en cache.</p> <p>Au niveau local, le mot de passe est stocké dans un attribut opérationnel : <em>ds-pta-cached-password</em>. On y trouve également la date de mise en cache du mot de passe.</p> <p>Par exemple :</p> <pre> <code>dn: cn=user1,ou=Externes,ou=People,dc=example,dc=com ds-pta-cached-password: {SSHA512}CpdBFPCD2LrQpDOFK+hjOifS+hwRz79yWYjMFS543iyAmHZIliBgHnoKjY+HhERC61eQMqNmkgEvrlXYtkmhyK9HK+0gqQQBraFUUd2TViM= ds-pta-cached-password-time: 20220404141914Z ds-pwp-password-policy-dn: cn=AuthServer_PTA_Policy,cn=Password Policies,cn=config </code></pre><h2>Migration progressive des mots de passe</h2> <p>En utilisant le mécanisme de cache et l'authentification en mode <em>pass through</em>, on pourra donc envisager de migrer progressivement les mots de passe de la manière suivante :</p> <ul><li>pour tous les utilisateurs qui doivent être migrés, assigner la politique de mot de passe de type "PTA Policy"</li> <li>pour les autres, on peut se reposer sur les politiques de mots de passe par défaut, ou celles définies dans les données (de type <em>subentry</em>)</li> </ul><p>Il faudra ensuite avoir un traitement complémentaire, qui sera lancé à intervalle régulier, et avec une fréquence supérieure à la durée de cache, qui va réaliser le traitement suivant :</p> <ul><li>rechercher les comptes qui ont l'attribut <em>ds_pta-cached-password</em> positionné, avec la politique de mot de passe "PTA"</li> <li>Pour ces comptes :</li> <li>mettre à jour l'attribut <em>userPassword</em> avec la valeur de l'attribut de cache</li> <li>supprimer l'assignation de la politique de mot de passe, pour récupérer celle définie par défaut.</li> </ul><p>Afin d'améliorer les performances, on pourra créer un index sur l'attribut :</p> <pre> <code>create-backend-index --backend-name amIdentityStore --index-name ds-pta-cached-password --type generic --set index-type:presence </code></pre><p>Ceci peut donc permettre d'utiliser les mots de passe actuels, tout en déconnectant au fil de l'eau le lien avec l'ancien annuaire.</p> <p>Au bout d'un certain temps, on pourra considérer que les comptes qui ont encore l'ancienne politique de mots de passe (ou qui n'ont pas encore d'attribut <em>userPassword</em>) ne sont pas utilisés, et on pourra faire un peu de "ménage", ou faire une campagne de renouvellement de mots de passe.</p> <p> </p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">lun 04/04/2022 - 17:09</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/index.php/tags/ds" hreflang="fr">ds</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=215&amp;2=comment_node_book&amp;3=comment_node_book" token="5eq-zcWEYJm_Yk06U0kNvELXXhjQF7kEMPtT6Lez1yY"></drupal-render-placeholder> </section> Mon, 04 Apr 2022 15:09:40 +0000 vincentl 215 at https://www.vincentliefooghe.net Utilisation d'attributs Json dans Forgerock DS https://www.vincentliefooghe.net/index.php/content/utilisation-dattributs-json-dans-forgerock-ds <span class="field field--name-title field--type-string field--label-hidden">Utilisation d&#039;attributs Json dans Forgerock DS</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Problématique</h2> <p>Il arrive des cas où l'utilisation des attributs "simples", qu'ils soient mono ou multi-valués, n'est pas satisfaisante par rapport aux besoins des utilisateurs.</p> <p>Prenons le cas suivant : on veut gérer des délégations pour X types de profils et chacun avec des rôles spécifiques.</p> <p>Soit :</p> <ul><li>délégation pour une société S1, avec les rôles RS1, RS2, RS3</li> <li>délégation pour une société S2, avec les rôles RS1, RS3</li> <li>délégation pour un utilisateur U1, avec les rôles RU1, RU2</li> </ul><p>Si on utilise un attribut de type chaîne de caractères, on peut s'en sortir avec des concaténations et des caractères de séparation. Par exemple :</p> <pre> <code>type|identifiant du type|role1-role2-role3 </code></pre><p>Dans ce cas on doit déjà gérer 2 types de séparateurs :le "|" pour les différents éléments, et le "-" pour les rôles.</p> <p>Dans notre exemple, ça donnerait :</p> <ul><li>societe|S1|RS1-RS2-RS3</li> <li>societe|S2|RS1-RS3</li> <li>utilisateur|U1|RU1-RU2</li> </ul><p>Par contre pour les recherches, ça devient plus compliqué, sauf à pré-calculer un filtre, en jouant avec les séparateurs.</p> <h2>Attribut Json</h2> <p>Depuis la version 5.5 (au moins), Forgerock permet d'utiliser une syntaxe Json dans les attributs, ce qui permet de gérer des données structurées à l'intérieur d'un attribut.</p> <h3>Déclaration dans le schéma</h3> <p>L'ajout d'un attribut de type JSON se fait de manière <em>traditionnelle</em>, en utilisant une syntaxe spécifique (<em>1.3.6.1.4.1.36733.2.1.3.1</em>).</p> <p>On ajoute ensuite les attributs dans le schéma :</p> <pre> <code>attributeTypes: ( 1.3.6.1.4.1.18472.2.101 NAME 'delegations' SYNTAX 1.3.6.1.4.1.36733.2.1.3.1 EQUALITY caseIgnoreJsonQueryMatch X-ORIGIN 'Mes tests json' ) attributeTypes: ( 1.3.6.1.4.1.18472.2.102 NAME 'jsonId' SYNTAX 1.3.6.1.4.1.36733.2.1.3.1 EQUALITY caseIgnoreJsonIdMatch SINGLE-VALUE X-ORIGIN 'Mes tests json' ) </code></pre><p>On doit également préciser le type de règle d'égalité qui sera utilisée. Il en existe 4 pré-définies :</p> <ul><li>caseIgnoreJsonQueryMatch : 2 objets sont identiques si tous leurs champs sont les mêmes, à la casse près</li> <li>caseExactJsonQueryMatch : 2 objets sont identiques si tous leurs champs sont les mêmes, avec la même casse de caractères</li> <li>caseIgnoreJsonIdMatch : 2 objets sont identiques si leur champ "_id" est identique, quelle que soit la casse de caractères</li> <li>caseExactJsonIdMatch : 2 objets sont identiques si leur champ "_id" est identique, avec la même casse de caractères.</li> </ul><p>Quelques exemples pour illustrer les cas. En supposant que j'ai 2 entrées dans l'annuaire LDAP, avec :</p> <ol><li>{"_id":"json","type":"user","value":"user123"}</li> <li>{"_id":"Json","type":"User","value":"USER123"}</li> <li>{"_id":"json","type":"user","value":"user345"}</li> <li>{"_id":"Json","type":"User","value":"USER345"}</li> </ol><p>Selon les cas :</p> <ul><li>avec la règle <strong>caseIgnoreJsonQueryMatch</strong>, les objets 1 et 2, et les objets 3 et 4 sont identiques</li> <li>avec la règle <strong>caseExactJsonQueryMatch</strong>, il n'y a pas de correspondance</li> <li>avec la règle <strong>caseIgnoreJsonIdMatch</strong>, les 4 objets sont identiques (ils ont le même _id)</li> <li>avec la règle <strong>caseExactJsonIdMatch</strong>, les objets 1 et 3 sont considérés identiques, ainsi que 2 et 4</li> </ul><h3>Indexation</h3> <p>Lorsqu'on indexe un attribut JSON, le comportement par défaut de Forgerock DS est de maintenir des clés pour chaque champ JSON. De ce fait, si l'attribut JSON contient de nombreux champs différents (et qui ne font pas l'objet de recherches) on peut choisir de n'indexer que ces champs. Dans ce cas, il faudra définir soi-même une règle (de type <em>json-equality-matching-rule</em>).</p> <p>Si on utilise une règle de comparaison basée sur l'ID uniquement, c'est ce champ qui sera indexé, et pas les autres.</p> <h3>Recherche</h3> <p>La syntaxe du filtre de recherche est la même que celle utilisée pour les API REST Forgerock (communément appelées CREST = Common REST).</p> <p>Quelques exemples de filtres, sur la base de nos attributs <em>delegations</em> et <em>jsonId</em> déclarés précédemment :</p> <pre> <code>delegations: {"type":"societe","attributions":[{"id":"societe1","roles":["role-soc1","role-soc2","role-soc3"]},{"id":"societe2","roles":["role-soc4"]}]} delegations: {"type":"utilisateur","attributions":[{"id":"user1","roles":["role-usr1","role-usr2"]},{"id":"user2","roles":["role-usr4"]}]} delegations: {"type":"org","attributions":[{"id":"org1","roles":["role-org1","role-org2","role-org4"]}] } jsonId: {"_id":"json","type":"user","value":"user123"} jsonId: {"_id":"Json","type":"User","value":"USER123"} jsonId: {"_id":"json","type":"user","value":"user345"} jsonId: {"_id":"Json","type":"User","value":"USER345"} </code></pre><ul><li>(delegations=*) : va renvoyer toutes les entrées qui ont un attribut <em>delegations</em></li> <li>(jsonid=_id eq 'json') va renvoyer les entrées qui ont la valeur 'json' dans le champ "_id" de l'attribut</li> <li>(delegations=type eq 'utilisateur' or type eq 'societe') : va renvoyer les objets ayant l'une ou l'autre valeur dans le champ type</li> </ul><p><strong>Limitations sur les filtres de recherche</strong></p> <p>Il n'est pas possible de faire une recherche dans un tableau qui contient plusieurs objets (attributions dans notre exemple).</p> <pre> <code>(delegations=id eq "user2") </code></pre><p>ne ramène rien (on n'y accède pas directement, il faudrait passer par attributions-&gt;id).</p> <p>Par contre, si on a une structure dont l'un des attributs est un tableau, qui ne contient que des valeurs, cela fonctionne.</p> <p>Si on a des attributs comme ceci :</p> <pre> <code>delegations: {"type":"utilisateur","id":"user1","roles":["role-usr1","role-usr2"]} delegations: {"type":"utilisateur","id":"user2","roles":["role-usr4","role-usr2"]} delegations: {"type":"societe","id":"societe1","roles":["role-soc1","role-soc2","role-soc3"]} delegations: {"type":"societe","id":"societe2","roles":["role-soc4"]} delegations: {"type":"org","id":"org2","roles":["role-org1","role-org2","role-org4"]} </code></pre><p>On peut bien faire des recherches de type :</p> <pre> <code>ldapsearch -b ou=people,dc=example,dc=com '(delegations=id eq "user2")' </code></pre><p>Si on veut éviter des collisions entre les différents types, on peut combiner plusieurs recherches. Si elles portent sur plusieurs éléments de l'attribut <em>json</em>, il faut utiliser le filtre adéquat. Par exemple :</p> <pre> <code>(delegations=id eq "2" and type eq "societe") </code></pre><p>La recherche dans un tableau fonctionne également. On peut ainsi rechercher tout les objets LDAP qui ont un role "role-usr4" :</p> <pre> <code>(delegations=roles eq "role-usr4") </code></pre><p>Idem pour les objets avec un type "societe" et un rôle "role-soc1" :</p> <pre> <code>(delegations=type eq "societe" and roles eq "role-soc1") </code></pre></div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">ven 04/03/2022 - 14:55</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/index.php/tags/ds" hreflang="fr">ds</a></div> <div class="field__item"><a href="/index.php/tags/json" hreflang="fr">json</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=214&amp;2=comment_node_book&amp;3=comment_node_book" token="sYSuQMghlx0xCAUDqXvngNEvgVyPnyCe-RJ6u6n_6dw"></drupal-render-placeholder> </section> Fri, 04 Mar 2022 13:55:34 +0000 vincentl 214 at https://www.vincentliefooghe.net Forgerock OpenDJ / DS - Supprimer les contrôles de syntaxe https://www.vincentliefooghe.net/index.php/content/forgerock-opendj-ds-supprimer-les-contr%C3%B4les-syntaxe <span class="field field--name-title field--type-string field--label-hidden">Forgerock OpenDJ / DS - Supprimer les contrôles de syntaxe</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Par défaut les nouveaux annuaires LDAP issus des sources OpenDS (tels que OpenDJ / DS chez Forgerock, mais aussi Ping Directory) renforcent les contrôles sur la syntaxe des attributs, le schéma, etc.</p> <p>Ceci empêche par exemple d'avoir un objet avec de multiples classes structurelles non hiérarchiques (par exemple <em>inetorgperson</em> et <em>country</em>).</p> <p>Par contre lorsqu'on importe des données d'un annuaire un peu moins strict (type Sun / Oracle DSEE), on se heurte souvent à des erreurs.</p> <p>La solution la plus propre est de modifier le fichier LDIF pour remettre au carré les données :</p> <ul><li>supprimer / modifier les attributs non conformes</li> <li>modifier le schéma pour éviter les héritages multiples</li> </ul><p>Mais ceci n'est pas toujours faisable.</p> <p>On peut alors relâcher les contrôles effectuer, en utilisant l'utilitaire <em>dsconfig </em>(testé depuis la version OpenDJ 2.6 jusque DS 7) :</p> <pre> #!/bin/bash PORT=5444 HOST=djlyreco BINDPASS="SuperPa$$w0rd" cd /path/to//opendj # Do not check schema bin/dsconfig set-global-configuration-prop --hostname $HOST --port ${PORT} --bindDN "cn=Directory Manager" \ --bindPassword ${BINDPASS} --set check-schema:false --trustAll --no-prompt # Allows multiple structural object classes (warning only) bin/dsconfig set-global-configuration-prop --hostname $HOST --port ${PORT} --bindDN "cn=Directory Manager" \ --bindPassword ${BINDPASS} --set single-structural-objectclass-behavior:warn --trustAll --no-prompt # Allows invalid attribute syntax bin/dsconfig set-global-configuration-prop --hostname $HOST --port ${PORT} \ --bindDN "cn=Directory Manager" --bindPassword ${BINDPASS} --set invalid-attribute-syntax-behavior:warn --trustAll --no-prompt # Allow pre-encoded passwords : pour l'import de compte avec des mots de passe existant bin/dsconfig -p ${PORT} -h $HOST -D "cn=Directory Manager" -w ${BINDPASS} \ set-password-policy-prop --policy-name "Default Password Policy" --set allow-pre-encoded-passwords:true -X -n</pre><p> </p> <p>La dernière ligne permet également d'importer des mots de passe pré-encodés. C'est utile en cas de migration de données entre annuaires, pour garder les mêmes mots de passe.</p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/user/1" typeof="schema:Person" property="schema:name" datatype="">Vincent</span></span> <span class="field field--name-created field--type-created field--label-hidden">mer 09/12/2020 - 11:30</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/ldap" hreflang="fr">ldap</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=208&amp;2=comment_node_book&amp;3=comment_node_book" token="FCUJHl0s_eMjKa8Cw3DvkSQUZ310pub5HrSmdbeosj4"></drupal-render-placeholder> </section> Wed, 09 Dec 2020 10:30:28 +0000 Vincent 208 at https://www.vincentliefooghe.net Upgrade Forgerock OpenDJ / DS https://www.vincentliefooghe.net/index.php/content/upgrade-forgerock-opendj-ds <span class="field field--name-title field--type-string field--label-hidden">Upgrade Forgerock OpenDJ / DS</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Deux scénarios de migration / upgrade seront étudiés :</p> <ul><li>upgrade "en place" d'un annuaire en version inférieure</li> <li>ajout dans la topologie de réplication d'un annuaire en version supérieure.</li> </ul><p>Dans cet exemple, on va procéder à une migration de la version OpenDJ 3.5.1 à la version DS 6.5.</p> <h2>Environnement</h2> <p>L'environnement de test est le suivant :</p> <p>3 serveurs : <em>dj1.id-num.com</em>, <em>dj2.id-num.com</em>, <em>dj3.id-num.com</em>.</p> <p>Dans un premier temps, seuls les serveurs dj1 et dj2 sont installés, en mode multi-maîtres :</p> <ul><li>O.S. CentOS 7</li> <li>Java jre 1.8</li> <li>OpenDJ 3.5.1, avec 2 annuaires répliqués</li> <li>Schéma de données <em>custom</em> avec attributs et classes d'objets spécifiques</li> <li>Annuaire installé dans le répertoire <code>/opt/opendj</code></li> <li>Index créé sur le serveur dj2, sur l'attribut <em>company</em></li> </ul><h3>Script d'installation</h3> <p>L'installation sur les 2 serveurs a été faite avec le script suivant :</p> <pre><code>#!/bin/sh # # Installation Forgerock OpenDJ 3.5.1 # #--------------------------------------- LDAPPORT=1389 PASS=ldapMaster REPLADM=replicationAdmin REPLPASS=replicationPassword ADMINPORT=4445 HOST1=dj1.id-num.com HOST2=dj2.id-num.com HOST3=dj3.id-num.com JAVAHOME=/opt/jre1.8.0_144 BASEDN="o=example" BASEDIR=/opt/opendj BINDIR=${BASESDIR}/bin export JAVA_HOME=${JAVAHOME} export OPENDJ_JAVA_HOME=${JAVAHOME} ${BASEDIR}/setup \ --cli \ --baseDN ${BASEDN} \ --addBaseEntry \ --ldapPort ${LDAPPORT} \ --adminConnectorPort ${ADMINPORT} \ --rootUserDN cn=Directory\ Manager \ --rootUserPassword ${PASS} \ --acceptLicense \ --no-prompt \ --noPropertiesFile </code></pre><h3>Script de réplication</h3> <p>La réplication est mise en place entre les serveurs <strong>dj1</strong> et <strong>dj2</strong>, via la commande :</p> <pre><code>${BINDIR}/dsreplication enable \ --host1 ${HOST1} --port1 ${ADMINPORT} \ --bindDN1 "cn=Directory Manager" \ --bindPassword1 ${PASS} \ --replicationPort1 8989 \ --host2 ${HOST2} --port2 ${ADMINPORT} \ --bindDN2 "cn=Directory Manager" \ --bindPassword2 ${PASS} \ --replicationPort2 8989 \ --adminUID ${REPLADM} \ --adminPassword ${REPLPASS} \ --baseDN ${BASEDN} \ --trustAll \ --no-prompt </code></pre><p>On peut ensuite lancer l'init, pour tous les serveurs de la topologie :</p> <pre><code>${BINDIR}/dsreplication \ initialize-all \ --adminUID ${REPLADM} \ --adminPassword ${REPLPASS} \ --baseDN ${BASEDN} \ --hostname $(hostname) \ --port ${ADMINPORT} \ --trustAll \ --no-prompt </code></pre><p>On vérifie, avec l'option <em>status</em> :</p> <pre><code>${BINDIR}/dsreplication status \ --adminUID ${REPLADM} \ --adminPassword ${REPLPASS} \ --port ${ADMINPORT} \ --trustAll \ --no-prompt Suffix DN : Server : Entries : Replication enabled : DS ID : RS ID : RS Port (1) : M.C. (2) : A.O.M.C. (3) : Security (4) ---------------------:---------------------:---------:---------------------:-------:-------:-------------:----------:--------------:------------- cn=Directory Manager : dj2.id-num.com:4445 : : : : : : : : o=example : dj1.id-num.com:4445 : 45 : true : 14774 : 27576 : 8989 : 0 : : false o=example : dj2.id-num.com:4445 : : true : 29513 : 481 : 8989 : 0 : : false </code></pre><h3>Schéma spécifique</h3> <p>Le schéma est modifié avec l'ajout de 2 attributs et une classe d'objet :</p> <pre><code>dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( partneruid-oid NAME 'partneruid' SUP name X-ORIGIN 'user Defined' ) attributeTypes: ( company-oid NAME 'company' SUP name X-ORIGIN 'user Defined' ) - add: objectclasses objectClasses: ( partnerperson-oid NAME 'partnerPerson' SUP inetorgperson MUST ( company ) MAY ( partneruid) ) </code></pre><h3>Version OpenDJ / DS</h3> <p>On peut vérifier la version actuelle avec la commande :</p> <pre><code>/opt/opendj/bin/dsconfig --version 3.5.1 (revision 23b322a7502f029b6d3725212c162de36f038122) </code></pre><h2>Upgrade "en place"</h2> <p>Il faut tout d'abord vérifier la trajectoire de migration supportée.</p> <p>Pour <em>Directory Services 6.5</em>, sorti fin 2018, la migration est supportée depuis la version OpenDJ 2.6 et supérieure.</p> <p>La version de Java est également à vérifier : Java 8 ou 11 pour DS 6.5. Nous utilisons une version 8 ce qui convient donc.</p> <p>Forgerock recommande de faire une sauvegarde <strong>physique</strong> du serveur à <em>upgrader</em>, en arrêtant l'annuaire et en faisant un <em>backup</em> de toute l'arborescence :</p> <pre><code>/opt/opendj/bin/stop-ds tar zcf opendj-3.5.tgz opendj </code></pre><p><strong>Note</strong> : l'upgrade en place nécessite d'arrêter l'instance d'annuaire qui va être migrée.</p> <h3>Procédure de migration</h3> <p>La procédure est simple ; elle consiste essentiellement à :</p> <ul><li>extraire l'archive de la nouvelle version au dessus de l'ancienne</li> <li>lancer la commande <strong>upgrade</strong></li> <li>vérifier et éventuellement adapter le paramétrage.</li> </ul><p>En détail :</p> <pre><code>cd /opt unzip /path/to/Software/Forgerock/DS-6.6.0.zip Archive: DS-6.6.0.zip creating: opendj/legal-notices/third-party-licenses/ creating: opendj/template/extlib/ creating: opendj/template/setup-profiles/ .../... creating: opendj/template/setup-profiles/IDM/repo/6.5/ creating: opendj/template/setup-profiles/IDM/repo/6.5/schema/ replace opendj/snmp/mib/rfc2605.txt? [y]es, [n]o, [A]ll, [N]one, [r]ename: y </code></pre><p>Répondre "A" pour écraser / remplacer les anciennes versions de fichiers.</p> <p>Lancer ensuite l'upgrade :</p> <pre><code>/opt/opendj/upgrade &gt;&gt;&gt;&gt; OpenDJ Upgrade Utility * OpenDJ configuration will be upgraded from version 3.5.1.23b322a7502f029b6d3725212c162de36f038122 to 6.5.0.e2a029a050cc6908fd144a6ca9c687e01ad56ea3 * OpenDJ data will be upgraded from version 6.0.0 to 6.5.0.e2a029a050cc6908fd144a6ca9c687e01ad56ea3 * See '/opt/opendj/logs/upgrade.log' for a detailed log of this operation &gt;&gt;&gt;&gt; Preparing to upgrade OpenDJ 5.5.0 changed the indexing algorithm for JSON equality matching rules. All JSON based attribute indexes must be rebuilt which may take a long time. Do you want to rebuild the indexes automatically at the end of the upgrade? (yes/no) [no]: yes OpenDJ 6.5.0 changed the indexing algorithm for replication metadata. Its index must be rebuilt which may take a long time; without a working index every server start will take longer than normal. Do you want to rebuild the index automatically at the end of the upgrade? (yes/no) [no]: yes The upgrade is ready to proceed. Do you wish to continue? (yes/no) [yes]: &gt;&gt;&gt;&gt; Performing upgrade Adding configuration for schema providers........................... 100% Adding configuration entry 'dn: cn=Core Schema,cn=Schema Providers,cn=config'................................................ 100% Removing top configuration entry for matching rules................. 100% Removing configuration for syntaxes................................. 100% .../... Replacing schema file '02-config.ldif'.............................. 100% Archiving concatenated schema....................................... 100% Migrating replication changelog files to 6.5.0 format............... 100% &gt;&gt;&gt;&gt; OpenDJ configuration was successfully upgraded from version 3.5.1.23b322a7502f029b6d3725212c162de36f038122 to 6.5.0.e2a029a050cc6908fd144a6ca9c687e01ad56ea3 &gt;&gt;&gt;&gt; OpenDJ data was successfully upgraded from version 6.0.0 to 6.5.0.e2a029a050cc6908fd144a6ca9c687e01ad56ea3 &gt;&gt;&gt;&gt; Performing post upgrade tasks Rebuilding index(es) '[.caseIgnoreJsonQueryMatch, .caseExactJsonQueryMatch, ds-sync-hist.changeSequenceNumberOrderingMatch]' for base dn(s) '[o=example]'....................................................... 100% &gt;&gt;&gt;&gt; Post upgrade tasks complete </code></pre><p>Les logs de la migration se trouvent dans <code>$DSHOME/logs/upgrade.log</code>.</p> <p>On peut ensuite démarrer l'instance, via la commande <code>bin/start-ds</code></p> <p>L'annuaire est bien passé en version supérieure :</p> <pre><code>/opt/opendj/bin/dsconfig --version 6.5.0 (revision e2a029a050cc6908fd144a6ca9c687e01ad56ea3) </code></pre><h3>Post Upgrade</h3> <p>Si on part d'une version inférieure à la version 5.5, Forgerock rcommande de donner des privilèges spécifiques au compte de réplication. Les privilèges à ajouter sont les suivants :</p> <ul><li>bypass-lockdown</li> <li>monitor-read</li> <li>server-lockdown</li> </ul><p>Ceci peut être fait en LDIF. Dans notre cas, le compte utilisé est <em>replicationAdmin</em> :</p> <pre><code>dn: cn=replicationAdmin,cn=Administrators,cn=admin data changetype: modify add: ds-privilege-name ds-privilege-name: bypass-lockdown ds-privilege-name: monitor-read ds-privilege-name: server-lockdown </code></pre><p>La modification n'est à faire qu'une seule fois, les données étant répliquées.</p> <p>L'upgrade peut ensuite être fait pour tous les serveurs de la topologie.</p> <h2>Ajout d'un nouveau serveur dans la topologie</h2> <p>Dans cette option, on va ajouter un nouveau serveur dans la topologie de réplication. Ceci peut donc être fait sans interruption de service.</p> <h3>Installation de DS 6.5</h3> <p>L'installation ds DS 6.5 se fait quasiment de la même manière que OpenDJ 3.5. Les seules différences : pas d'option <em>--cli</em> et l'option <em>--hostname</em> qui est obligatoire.</p> <pre><code>LDAPPORT=1389 PASS=ldapMaster REPLADM=replicationAdmin REPLPASS=replicationPassword ADMINPORT=4445 HOST1=dj1.id-num.com HOST2=dj2.id-num.com HOST3=dj3.id-num.com JAVAHOME=/opt/jre1.8.0_144 BASEDN="o=example" BASEDIR=/opt/opendj BINDIR=${BASESDIR}/bin export JAVA_HOME=${JAVAHOME} export OPENDJ_JAVA_HOME=${JAVAHOME} /opt/opendj/setup \ --hostname ${HOST3} \ --baseDN ${BASEDN} \ --addBaseEntry \ --ldapPort ${LDAPPORT} \ --adminConnectorPort ${ADMINPORT} \ --rootUserDN cn=Directory\ Manager \ --rootUserPassword ${PASS} \ --acceptLicense </code></pre><p>A ce stade, on a donc un annuaire en mode "standby". Nous pouvons l'inclure dans le domaine de réplication.</p> <h3>Ajout dans la réplication</h3> <p>Forgerock recommande d'utiliser la commande <em>dsreplication</em> du nouveau serveur pour l'ajouter dans une topologie de réplication existante.</p> <p>La commande pour configurer une nouvelle réplication utilise maintenant l'option <em>configure</em> plutôt que <em>enable</em> :</p> <pre><code>${BINDIR}/dsreplication configure \ --host1 ${HOST1} --port1 4445 \ --bindDN1 "cn=Directory Manager" \ --bindPassword1 ${PASS} \ --replicationPort1 8989 \ --host2 ${HOST3} --port2 4445 \ --bindDN2 "cn=Directory Manager" \ --bindPassword2 ${PASS} \ --replicationPort2 8989 \ --adminUID ${REPLADM} \ --adminPassword ${REPLPASS} \ --baseDN ${BASEDN} \ --trustAll \ --no-prompt </code></pre><h3>Initialisation de la réplication</h3> <p>On peut maintenant lancer l'initialisation de la réplication sur un seul serveur. Avec l'option <em>initialize</em> plutôt que <em>initialize-all</em> il faut préciser les serveurs sources et destinations :</p> <pre><code>${BINDIR}/dsreplication initialize \ --adminUID ${REPLADM} \ --adminPassword ${REPLPASS} \ --baseDN ${BASEDN} \ --hostSource ${HOST1} \ --portSource ${ADMINPORT} \ --hostDestination ${HOST2} \ --portDestination ${ADMINPORT} \ --trustAll \ --no-prompt </code></pre><p>On peut ensuite vérifier :</p> <pre><code>Suffix DN : Server : Entries : Replication enabled : DS ID : RS ID : RS Port (1) : Delay (ms) : Security (2) ----------:---------------------:---------:---------------------:-------:-------:-------------:------------:------------- o=example : dj1.id-num.com:4445 : 2025 : true : 14774 : 27576 : 8989 : N/A : false o=example : dj2.id-num.com:4445 : 2025 : true : 29513 : 481 : 8989 : 0 : false o=example : dj3.id-num.com:4445 : 2025 : true : 706 : 30128 : 8989 : 0 : false </code></pre><p>Une fois que l'on a ajouté le nouveau serveur, il faut éventuellement paramétrer les éléments propres à l'instance (par exemple les index) qui sont positionnés via l'utilitaire <em>dsconfig</em>.</p> <h3>Adaptations et différences</h3> <p>On peut trouver quelques différences entre OpenDJ 3.5 et DS 6.5. A première vue, on peut citer :</p> <ul><li>les options des commandes <em>dsconfig</em> ou <em>dsreplication</em></li> <li>les fichiers de définition du schéma qui ont migré de <code>DJ_HOME/config/schema</code> à <code>DS_HOME/db/schema</code></li> </ul><h2>Synthèse</h2> <p>Nous avons vu que deux possibilités sont offertes pour faire un <em>upgrade</em>, de manière assez simple.</p> <p>L'upgrade "en place" est intéressant pour récupérer toute la configuration spécifique de l'instance (paramètres positionnés par l'utilitaire <strong>dsconfig</strong> et qui ne sont pas répliqués). Dans ce cas, on garde le même serveur, et donc la même version d'O.S., de java, et d'adresse IP.</p> <p>Cependant, ceci nécessite d'arrêter l'une des instances de la topologie de réplication.</p> <p>L'ajout d'une nouvelle instance peut se justifier si on veut changer de version d'O.S. et/ou limiter au maximum les interruptions de service. Cela permet aussi d'adapter les scripts aux nouvelles versions d'outils (<strong>même si l'environnement de Test est fait pour cela</strong>). Par contre, ceci implique de reprendre le paramétrage de la configuration.</p> <table><tbody><tr><th>Méthode</th> <th>Avantages</th> <th>Inconvénients</th> </tr><tr><th>Upgrade en place</th> <td>Pas de changement d'adresse IP<br />Récupération de la configuration</td> <td>Arrêt de l'instance</td> </tr><tr><th>Ajout d'une nouvelle instance</th> <td>Possibilité de monter de version d'O.S.<br />Pas d'arrêt de serveur<br />Possibilité de tester les outils</td> <td>Nouveau serveur à provisionner<br />Nouvelle adresse IP à gérer<br />Pas de récupération du paramétrage spécifique</td> </tr></tbody></table><p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">ven 14/12/2018 - 22:06</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Fri, 14 Dec 2018 21:06:26 +0000 vincentl 197 at https://www.vincentliefooghe.net LDAP : les types de groupes https://www.vincentliefooghe.net/index.php/content/ldap-les-types-groupes <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">LDAP : les types de groupes</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Les annuaires LDAP sont principalement utilisés pour gérer 2 types d'objets :</p> <ul><li>les comptes utilisateurs (qui vont permettre une authentification centralisée)</li> <li>des groupes d'utilisateurs (qui vont permettre une gestion de droits).</li> </ul><p>D'autres objets annexes sont souvent ajoutés, qui ont un rôle de <em>"listes de valeurs"</em>.</p> <p>Nous allons voir dans cet article les différents types de groupes qui peuvent être utilisés, sachant que selon les RFC LDAP 4519, seuls les premiers sont vraiment standardisés.</p> <h2>Groupes statiques</h2> <p>A l'origine, les groupes statiques, définis par les classes d'objet <em>groupOfNames</em> et <em>groupOfUniqueNames</em> sont juste une liste de membres (donnés par leur DN).</p> <p>Dans un groupe de type <em>groupOfNames</em>, l'attribut utilisé est <em>member</em>, et on peut avoir plusieurs fois le même membre.</p> <p>Dans un groupe de type <em>groupOfUniqueNames</em>, l'attribut utilisé est <em>uniqueMember</em>, et on peut avoir une seule occurence pour chaque membre.</p> <p>Exemple :</p> <pre><code>dn: cn=firstGroup,ou=Groups,dc=example,dc=com objectclass: top objectclass: groupofnames member: uid=john.doe,ou=People,dc=example,dc=com cn: firstGroup </code></pre><p>On peut donc récupérer facilement tous les membres d'un groupe statique, en listant les valeurs de l'attribut <em>uniqueMember</em> ou <em>member</em>, selon le cas. De même, pour connaître les groupes affectés à un utilisateur, on utilisera une recherche du type :</p> <pre><code>ldapsearch -b "dc=example,dc=com" -s sub "(|(&amp;(objectClass=groupOfNames)(member=uid=john.doe,ou=People,dc=example,dc=com)) \ (&amp;(objectClass=groupOfUniqueNames) (uniqueMember=uid=john.doe,ou=People,dc=example,dc=com)) </code></pre><h3>Avantages</h3> <p>C'est le seul type de groupe standardisé, et qui peut donc être utilisé par la plupart des applications ou équipements. Certains équipements réseaux par exemple peuvent utiliser les groupes pour valider les habilitations.</p> <h3>Inconvénients</h3> <p>Le principal inconvénient est la maintenance de ces groupes, puisque l'ajout ou le retrait des membres se fait de manière unitaire. Par défaut il n'y a pas de contrôle de cohérence, on peut donc ajouter comme membre d'un groupe un DN inexistant ; et si on supprime un utilisateur, son DN peut encore apparaître dans la liste des membres.</p> <p><strong>Note</strong> : certains annuaires utilisent un <em>plugin</em> d'intégrité référentiel, qui permet, à la suppression de l'entrée utilisateur, d'aller supprimer le DN correspondant des membres des groupes.</p> <h2>Groupes dynamiques</h2> <p>Il n'y a pas de définition formelle de type RFC pour les groupes dynamiques. L'implémentation dépend du fournisseur d'annuaire. Sur OpenLDAP par exemple, on trouve un <em>overlay</em> <strong>dynlist</strong> qui permet d'apporter cette fonctionnalité.</p> <p>Sur les annuaires tels que Sun/Oracle DSEE, OpenDS et ses descendants (Forgerock OpenDJ, Oracle OUD, UnboundID/Ping Drectory), on utilise un groupe de type <em>groupOfUrls</em>.</p> <p>Les groupes dynamiques utilisent un attribut <em>memberURL</em> qui permet de définir une requête LDAP, de la forme ldap:///BASE_DN?ATTRIBUTS?SCOPE?FILTRE.</p> <p>Exemples de filtres :</p> <pre><code>ldap:///ou=People,dc=example,dc=com?uid,cn,sn?sub?(departmentNumber=IT) </code></pre><p>Recherche à partir de la base DN <code>ou=People,dc=example,dc=com</code>, avec un <em>scope</em> de type <code>subtree</code>, les utilisateurs qui sont dans le département IT, et récupère uniquement les attributs <em>uid, sn</em> et <em>cn</em>.</p> <p>Exemple :</p> <pre><code>dn: cn=IT-Staff,ou=Groups,dc=example,dc=com objectclass: top objectclass: groupOfURLs cn: IT-staff memberURL: ldap:///ou=People,dc=example,dc=com??sub?(departmentNumber=IT) </code></pre><h3>Avantages</h3> <p>Une fois que le filtre est défini, la gestion des membres est automatique, puisque basée sur les attributs de l'utilisateur.</p> <h3>Inconvénients</h3> <p>Par défaut, ce sont les clients qui doivent interpréter la requête LDAP présente dans l'attribut <em>memberURL</em>. On ne peut pas avoir la liste des membres rien qu'en faisant une requête sur le groupe, et on ne peut pas non plus avoir la liste des groupes d'un utilisateur en cherchant son DN dans les membres.</p> <p>Pour pallier ce problème, la plupart des annuaires qui implèmentent les groupes dynamiques gèrent aussi un attribut virtuel <strong>isMemberOf</strong>, qui contient la liste des groupes dont l'utilisateur est membre.</p> <h2>Exemples</h2> <p>Si on injecte le contenu du fichier LDIF suivant dans un annuaire :</p> <pre><code>dn: ou=staff,ou=people,dc=example,dc=com objectClass: organizationalunit objectClass: top ou: staff dn: uid=john.doe,ou=staff,ou=people,dc=example,dc=com givenName: John objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top uid: john.doe cn: John Doe sn: Doe departmentNumber: Finance dn: uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com givenName: Elliot objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top uid: elliot.alderson cn: Elliot Alderson sn: Alderson departmentNumber: IT dn: uid=angela.moss,ou=staff,ou=people,dc=example,dc=com givenName: Angela objectClass: person objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: top uid: angela.moss cn: Angela Moss sn: Moss departmentNumber: IT dn: ou=Groups,dc=example,dc=com objectClass: organizationalunit objectClass: top ou: Groups dn: cn=Staff,ou=Groups,dc=example,dc=com objectclass: top objectclass: groupofnames member: uid=john.doe,ou=staff,ou=people,dc=example,dc=com member: uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com member: uid=angela.moss,ou=staff,ou=people,dc=example,dc=com cn: Staff dn: cn=IT-Staff,ou=Groups,dc=example,dc=com objectclass: top objectclass: groupOfURLs cn: IT-staff memberURL: ldap:///ou=People,dc=example,dc=com??sub?(departmentNumber=IT) </code></pre><p>La recherche des groupes liés à Elliot Anderson donne le résultat suivant :</p> <pre><code>ldapsearch -b ou=groups,dc=example,dc=com member=uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com dn dn: cn=Staff,ou=Groups,dc=example,dc=com </code></pre><p>On ne trouve pas le groupe dynamique lié. Par contre, si on utilise l'attribut <em>isMemberOf</em>, on va avoir tous les groupes :</p> <pre><code>ldapsearch -b ou=people,dc=example,dc=com uid=elliot.alderson ismemberof dn: uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com ismemberof: cn=Staff,ou=Groups,dc=example,dc=com ismemberof: cn=IT-Staff,ou=Groups,dc=example,dc=com </code></pre><h2>Groupes statiques virtuels</h2> <p>Pour tenter de concilier les avantages des deux types de groupes, certains annuaires implémentent un nouveau type de groupe : le groupe Virtuel Static <em>Virtual Static Groups</em>).</p> <p>Les groupes virtuels statiques utilisent une classe d'objet spécifique, <em>ds-virtual-static-group</em>, et font référence à un groupe dynamique (qu'il faudra donc créer auparavant).</p> <p>Exemple :</p> <pre><code>dn: cn=VS-IT-staff,ou=Groups,dc=example,dc=com cn: VS-IT-staff objectclass: top objectclass: groupOfNames objectclass: ds-virtual-static-group ds-target-group-dn: cn=IT-Staff,ou=Groups,dc=example,dc=com </code></pre><p>Si on ajoute le groupe, on le récupère dans l'attribut <em>isMemberOf</em> de l'utilisateur. Par exemple ;</p> <pre><code>/opt/opendj/bin/ldapsearch -b ou=staff,ou=people,dc=example,dc=com uid=elliot.alderson ismemberof dn: uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com ismemberof: cn=Staff,ou=Groups,dc=example,dc=com ismemberof: cn=IT-Staff,ou=Groups,dc=example,dc=com ismemberof: cn=VS-IT-staff,ou=Groups,dc=example,dc=com </code></pre><p>Par contre par défaut le groupe virtuel statique ne donne pas la liste de ses membres :</p> <pre><code>ldapsearch -b ou=Groups,dc=example,dc=com cn=VS-IT-staff dn: cn=VS-IT-staff,ou=Groups,dc=example,dc=com cn: VS-IT-staff ds-target-group-dn: cn=IT-Staff,ou=Groups,dc=example,dc=com objectClass: groupOfNames objectClass: ds-virtual-static-group objectClass: top </code></pre><h3>Pour récupérer la liste des membres</h3> <p>La récupération de la liste des membres d'un groupe virtuel statique se fait à la volée, et peut donc être consommatrice de ressources, surtout sur de grosses volumétrie. La fonctionnalité est désactivée par défaut. On peut l'activer avec l'utilitaire <strong>dsconfig</strong> :</p> <pre><code>dsconfig set-virtual-attribute-prop --name "Virtual Static member" --set allow-retrieving-membership:true </code></pre><p>Si on recherche directement le groupe , on a bien la liste des membres :</p> <pre><code>ldapsearch -b ou=Groups,dc=example,dc=com cn=VS-IT-staff dn: cn=VS-IT-staff,ou=Groups,dc=example,dc=com member: uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com member: uid=angela.moss,ou=staff,ou=people,dc=example,dc=com cn: VS-IT-staff ds-target-group-dn: cn=IT-Staff,ou=Groups,dc=example,dc=com objectClass: groupOfNames objectClass: ds-virtual-static-group objectClass: top member: uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com member: uid=angela.moss,ou=staff,ou=people,dc=example,dc=com </code></pre><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ce type de groupe peut donc être utilisé si une application cliente veur récupérer la liste des membres, à partir du nom du groupe. Par contre, si on fait une recherche sur les membres, le groupe n'apparaît pas non plus :</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <pre style="margin: 0px; text-indent: 0px;">ldapsearch -b ou=groups,dc=example,dc=com member=uid=elliot.alderson,ou=staff,ou=people,dc=example,dc=com dn dn: cn=Staff,ou=Groups,dc=example,dc=com</pre><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Seul l'attribut <em>isMemberOf</em> contient l'ensemble des groupes affectés à la personne.</p> <style type="text/css"> <!--/*--><![CDATA[/* ><!--*/ <!--/*--><![CDATA[/* ><!--*/ p, li { white-space: pre-wrap; } /*--><!]]]]><![CDATA[>*/ /*--><!]]>*/ </style><pre><code> </code></pre></div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2018-04-30T09:20:07+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">lun 30/04/2018 - 11:20</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/ldap" hreflang="fr">ldap</a></div> <div class="field__item"><a href="/index.php/tags/ping-directory" hreflang="fr">ping directory</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Mon, 30 Apr 2018 09:20:07 +0000 vincentl 192 at https://www.vincentliefooghe.net Création de comptes Administrateurs dans OpenDJ / Ping Directory https://www.vincentliefooghe.net/index.php/content/cr%C3%A9ation-comptes-administrateurs-dans-opendj-ping-directory <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Création de comptes Administrateurs dans OpenDJ / Ping Directory</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Lorsqu'on installe un annuaire LDAP, on crée un compte (souvent "<em>cn=Directory Manager</em>" par défaut) qui a tous les privilèges, qui n'est pas soumis aux ACI, bref, un superAdmin avec tous les privilèges.</p> <p>Il vaut donc mieux éviter d'utiliser ce compte pour des opérations. On peut toujours utiliser des comptes "utilisateurs", mais dans ce cas, le DN du compte change selon le baseDN.</p> <p>Si on veut industrialiser le monitoring de l'annuaire, par exemple, il est intéressant d'avoir toujours le même compte, quel que soit l'instance et donc le baseDN.</p> <p>C'est ici qu'interviennent les Root DNs, qui sont stockés dans la configuration (le <em>cn=config</em>).</p> <ul><li>Avantage : le DN sera le même sur tous les annuaires</li> <li>Inconvénient : le cn=config n'étant pas répliqué, il faut répéter la création sur chaque instance</li> </ul><p>OpenDJ et Ping Directory sont des annuaires "cousins", bâtis sur les sources de OpenDS après le rachat de Sun Microsystems par Oracle. Les deux produits ont divergé au fil du temps, mais les principes restent similaires. Nous allons voir les commandes à lancer sur les 2 produits.</p> <h2>OpenDJ</h2> <p>Avec OpenDJ, il faut ajouter une entrée dans le cn=config, via un fichier LDIF et un ldapmodify :</p> <pre>cat /tmp/monitor.ldif dn: cn=LDAP Monitoring,cn=Root DNs,cn=config changetype: add objectClass: ds-cfg-root-dn-user objectClass: top objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person sn: Monitoring cn: LDAP Monitoring givenName: LDAP ds-privilege-name: config-read ds-privilege-name: metrics-read ds-privilege-name: unindexed-search ds-cfg-alternate-bind-dn: cn=ldapMonitoring userPassword: Ld@pM0n|T0R1n6 </pre><p>On intègre ensuite les données :</p> <pre>/opt/opendj/bin/ldapmodify -D "cn=Directory Manager" -w secret -f /tmp/monitor.ldif</pre><p>A ce niveau on peut se connecter avec cn=ldapMonitoring, sans devoir passer le DN complet.</p> <p>On peut par exemple récupérer les informations du <em>cn=monitor</em> :</p> <pre>ldapsearch -x -h localhost -p 1389 -D cn=ldapMonitoring -w Ld@pM0n|T0R1n6 -b cn=monitor (objectclass=ds-monitor-entry)</pre><h2>Ping Directory</h2> <p>Ping Directory a nettement enrichi l'utilitaire <em>dsconfig</em>, en ajoutant des dizaines d'option par rapport à ses prédécesseurs.</p> <p>La création d'un compte de type Root DN passe maintenant par l'utilitaire dsconfig, avec l'option create-root-dn-user.</p> <pre>/opt/ping/bin/dsconfig create-root-dn-user --bindDN "cn=Directory Manager" --bindPassword secret --user-name ldapMonitoring \ --set alternate-bind-dn:cn=ldapMonitoring --set first-name:LDAP --set inherit-default-root-privileges:false --set last-name:Monitoring \ --set 'password:Ld@pM0n|T0R1n6' --set privilege:config-read --set privilege:metrics-read --set privilege:unindexed-search --no-prompt</pre><p>Par rapport à OpenDJ, sur lequel tous les utilisateurs authentifiés peuvent accéder aux données de cn=monitor, Ping Directory ne donne pas d'accès par défaut. Il faut donc ajouter une global ACI sur cette entrée :</p> <pre>/opt/ping/bin/dsconfig set-access-control-handler-prop --bindPassword secret \ --add global-aci:'(target="ldap:///cn=monitor")(targetattr="*")(version 3.0; acl "Allow access to the monitor tree by ldapMonitoring"; allow(all) userdn="ldap:///cn=ldapMonitoring,cn=Root DNS,cn=config";)' --no-prompt</pre><p> </p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2018-04-04T08:08:30+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">mer 04/04/2018 - 10:08</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/index.php/tags/ping-directory" hreflang="fr">ping directory</a></div> <div class="field__item"><a href="/index.php/tags/unboundid" hreflang="fr">unboundid</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Wed, 04 Apr 2018 08:08:30 +0000 vincentl 191 at https://www.vincentliefooghe.net OpenDJ : mise en place du suivi des connexions https://www.vincentliefooghe.net/index.php/content/opendj-mise-place-du-suivi-des-connexions <span class="field field--name-title field--type-string field--label-hidden">OpenDJ : mise en place du suivi des connexions</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Par défaut, il n'est pas possible de déterminer la date de dernière connexion réussie sur un annuaire LDAP (last login time). Seules les erreurs de connexion peuvent être détectées dans les politiques de mots de passe.</p> <p>Parfois cependant, il est intéressant de connaître la date de dernière connexion, afin de pouvoir supprimer - ou bloquer - des comptes inutilisés depuis plusieurs mois.</p> <p>Certains annuaire permettent de modifier les politiques de mots de passe pour tracer les connexions réussies, mais ceci a un impact sur les authentifications. En effet, à chaque authentification réussie, l'annuaire doit écrire la date de connexion sur l'objet utilisateur. On passe donc d'une suite d'opérations <em>search and bind</em> à une suite <em>search and bind and mod</em>.</p> <p>Quel est donc l'impact de ce suivi sur les performances d'un annuaire ? C'est l'objet de ce test, réalisé sur un annuaire LDAP Forgerock Opendj (DS 5.5).</p> <h2>Configuration utilisée</h2> <p>La configuration utilisée est la suivante :</p> <ul><li>2 vCPU Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz</li> <li>16 Go de RAM</li> </ul><p>Le jeu de test est constitué d'un fichier LDIF de 481 Mo, comprenant 220 000 entrées utilisateur.</p> <p>Parmi ces 220 000 entrées, 50 000 sont situées dans une OU (<em>organizational unit</em>) spécifique : ou=People,ou=FR,o=example.</p> <h2>Politique de mots de passe par défaut</h2> <p>La politique de mot de passe par défaut est utilisée, avec le chargement des entrées.</p> <pre><code>Property : Value(s) ------------------------------------------:------------------------------------ account-status-notification-handler : - allow-expired-password-changes : false allow-multiple-password-values : false allow-pre-encoded-passwords : false allow-user-password-changes : true default-password-storage-scheme : Salted SHA-512 deprecated-password-storage-scheme : - expire-passwords-without-warning : false force-change-on-add : false force-change-on-reset : false grace-login-count : 0 idle-lockout-interval : 0 s java-class : org.opends.server.core.PasswordPolicyFactory last-login-time-attribute : - last-login-time-format : - lockout-duration : 0 s lockout-failure-count : 0 lockout-failure-expiration-interval : 0 s max-password-age : 25 w 5 d max-password-reset-age : 0 s min-password-age : 0 s password-attribute : userPassword password-change-requires-current-password : false password-expiration-warning-interval : 5 d password-generator : Random Password Generator password-history-count : 5 password-history-duration : 0 s password-validator : Length-Based Password Validator previous-last-login-time-format : - require-change-by-time : - require-secure-authentication : false require-secure-password-changes : false skip-validation-for-administrators : false state-update-failure-policy : reactive </code></pre><h2>Outils de benchmark</h2> <p>Les tests sont lancés avec les utilitaires <em>authrate</em> et <em>searchrate</em>, qui sont intégrés aux binaires de l'annuaire.</p> <p>Pour la recherche :</p> <p><style type="text/css"> <!--/*--><![CDATA[/* ><!--*/ <!--/*--><![CDATA[/* ><!--*/ p, li { white-space: pre-wrap; } /*--><!]]]]><![CDATA[>*/ /*--><!]]>*/ </style></p> <pre style="margin: 0px; text-indent: 0px;">/opt/opendj/bin/searchrate -h 10.150.29.161 -p 1389 -D 'uid=user.1,ou=people,ou=fr,o=example' -w password -F -c 10 -b o=example -m 300000 -g 'rand(100,49000)' '(uid=user.%d)'</pre><p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p>Pour les authentifications, en mode search + bind :</p> <pre><code>/opt/opendj/bin/authrate -h 10.150.29.161 -p 1389 -D '%2$s' -w password -f -c 10 -b ou=people,ou=fr,o=example -s sub -m 300000 -g 'rand(100,49000)' '(uid=user.%d)' </code></pre><h2>Procédure de tests</h2> <p>La procédure de tests est la suivante :</p> <ul><li>démarrage de l'annuaire</li> <li>lancement d'un premier test de type <em>searchrate</em>, qui permet de cacher les entrées en RAM</li> <li>lancement d'un test d'authentification avec <em>authrate</em> en mode search + bind</li> </ul><h2>Mesures sans suivi de la date de dernière connexion</h2> <p>Avec le paramétrage par défaut, on obtient un débit moyen de 4283 authentifications par seconde, avec un temps de réponse moyen de 2.131 millisecondes.</p> <pre><code>------------------------------------------------------------------------------ Throughput Response Time (ops/second) (milliseconds) recent average recent average 99.9% 99.99% 99.999% err/sec bind time % ------------------------------------------------------------------------------ 3901.6 3907.1 2.573 2.573 25.304 162.729 167.620 0.0 44.4 4186.4 4047.8 2.372 2.469 26.546 166.949 195.819 0.0 46.6 4540.4 4212.9 2.183 2.365 23.388 166.223 195.819 0.0 44.2 4624.0 4315.7 2.147 2.307 22.435 162.729 195.819 0.0 42.6 4609.7 4374.6 2.156 2.275 22.083 160.540 172.100 0.0 43.0 4663.1 4422.7 2.130 2.250 21.634 158.399 172.100 0.0 42.5 4765.9 4471.7 2.088 2.225 21.431 154.617 172.100 0.0 42.8 4764.9 4508.4 2.089 2.207 20.982 141.395 172.100 0.0 42.0 4864.1 4547.9 2.050 2.188 21.024 39.778 169.393 0.0 42.2 4811.6 4574.2 2.077 2.177 20.934 34.832 169.393 0.0 42.0 4777.0 4592.6 2.091 2.169 20.525 32.932 169.393 0.0 41.8 4825.5 4611.9 2.072 2.160 20.090 32.724 169.393 0.0 41.9 4101.4 4572.6 1.898 2.142 19.807 32.213 169.393 0.0 41.7 530.8 4283.0 0.869 2.131 19.703 32.118 167.620 0.0 41.0 </code></pre><p>La CPU est utilisée à 90 % environ sur le serveur cible (qui dispose de 2 vCPU).</p> <h2>Mise en place du suivi du <em>last login time</em></h2> <h3>Création d'un attribut spécifique</h3> <p>La mise en place du suivi demande tout d'abord de créer un attribut qui sera utilisé pour stocker la date de dernière connexion. La documentation donne justement un exemple de politique de mots de passe qui met en oeuvre le suivi.</p> <pre><code>dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( lastLoginTime-oid NAME 'lastLoginTime' DESC 'Last time the user logged in' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'OpenDJ example documentation' ) </code></pre><p>On ajoute l'attribut au schéma via la commande <em>ldapmodify</em> :</p> <pre><code>ldapmodify \ --hostname localhost \ --port 1389 \ --bindDN "cn=Directory Manager" \ --bindPassword password \ lastLoginTime.ldif </code></pre><h3>Création d'une politique de mots de passe spécifique</h3> <p>Si on veut cibler certains comptes utilisateurs, on peut créer une politique de mots de passe spécifiquement pour cet usage :</p> <pre><code>/opt/opendj/bin/dsconfig \ create-password-policy \ --hostname localhost --port 4444 \ --bindDN "cn=Directory Manager" \ --bindPassword password \ --policy-name "Track Last Login Time" \ --type password-policy \ --set default-password-storage-scheme:"Salted SHA-512" \ --set password-attribute:userPassword \ --set last-login-time-attribute:lastLoginTime \ --set last-login-time-format:"yyyyMMddHH'Z'" \ --trustAll \ --no-prompt </code></pre><h3>Modification de la politique de mots de passe</h3> <p>On peut créer une nouvelle politique de mots de passe, ou modifier la politique existante. Dans ce cas, la commande à utiliser est la suivante :</p> <pre><code>/opt/opendj/bin/dsconfig set-password-policy-prop \ --policy-name Default\ Password\ Policy \ --set last-login-time-attribute:lastLoginTime \ --set last-login-time-format:"yyyyMMddHH'Z'" \ --hostname localhost \ --port 4444 \ --bindDn cn=Directory\ Manager \ --bindPassword password \ --trustAll \ --no-prompt </code></pre><h2>Test sur une entrée</h2> <p>Si on fait une requête avec un utilisateur en se connectant, on peut ensuite récupérer la date de dernière connexion sur son entrée, à condition de disposer des droits adéquats.</p> <p>Par exemple :</p> <pre><code>ldapsearch -x -h localhost -p 1389 -D 'cn=Directory Manager' -w password -b o=example '(uid=user.2)' lastLoginTime dn: uid=user.2,ou=People,ou=FR,o=example lastLoginTime: 2017121909Z </code></pre><p>On constate que la date est bien au format déclaré, c'est à dire comprenant l'année, le mois, le jour et l'heure. En effet, il n'est pas nécessaire de suivre les connexions à la minute près.</p> <h2>Mesures AVEC suivi de la date de dernière connexion</h2> <p>Avec le nouveau paramétrage, incluant la mise à jour de la dernière date de connexion, on obtient un débit maximum de 2860 authentifications par seconde en moyenne, avec un temps de réponse moyen de 3.382 millisecondes.</p> <p>La charge CPU sur le serveur d'annuaire oscille entre 50 et 95%, avec des I/O wait.</p> <p>On a bien un impact assez fort, avec notamment des phases pendant laquelle l'annuaire est en I/O wait, révélateur des mises à jour effectuées sur les entrées.</p> <pre><code>------------------------------------------------------------------------------ Throughput Response Time (ops/second) (milliseconds) recent average recent average 99.9% 99.99% 99.999% err/sec bind time % ------------------------------------------------------------------------------ 1570.3 1573.1 6.421 6.421 152.833 177.026 177.026 0.0 63.6 2308.4 1942.2 4.325 5.170 53.701 176.974 177.026 0.0 57.0 2479.4 2122.0 4.023 4.722 49.889 165.267 177.026 0.0 53.3 1025.2 1847.4 3.712 4.581 48.670 165.267 177.026 0.0 51.6 0.0 1477.0 - 4.581 48.670 165.267 177.026 0.0 NaN 1013.4 1399.8 25.871 7.149 50.589 11195.648 11204.023 0.0 93.5 2996.8 1627.5 3.332 6.147 46.142 11193.992 11204.023 0.0 49.8 3301.1 1836.1 3.028 5.447 44.262 11187.622 11204.023 0.0 48.4 3329.9 2001.8 2.737 4.948 41.735 11165.580 11204.023 0.0 47.0 0.0 1800.9 - 4.948 41.735 11165.580 11204.023 0.0 NaN 92.4 1645.4 226.166 6.078 43.042 11156.315 11204.023 0.0 99.2 4024.9 1843.1 2.485 5.426 39.488 10339.090 11203.705 0.0 45.4 4193.7 2023.6 2.382 4.942 38.478 10328.566 11203.705 0.0 44.3 4487.2 2199.3 2.227 4.547 36.814 10316.059 11203.705 0.0 43.1 4496.0 2352.3 2.222 4.251 35.540 10313.618 11203.705 0.0 43.3 4530.5 2488.3 2.207 4.018 34.530 10213.330 11203.705 0.0 43.0 4535.5 2608.8 2.204 3.833 33.649 168.792 11202.112 0.0 43.3 4479.8 2712.7 2.230 3.686 33.112 163.941 11202.112 0.0 42.7 4722.0 2818.5 2.116 3.547 32.285 160.038 11202.112 0.0 42.6 4710.9 2913.1 2.108 3.431 31.666 79.285 11202.112 0.0 42.5 1816.5 2860.5 1.834 3.382 31.418 75.221 11195.866 0.0 42.9 </code></pre><p><em>Note</em> : ceci est cependant à modérer, puisque notre première campagne de tir va déclencher une écriture pour chaque utilisateur qui s'authentifie. Si on relance un deuxième tir dans l'heure (qui est l'unité minimale de suivi de la date de connexion), on retrouve des résultats quasiment identiques au premier cas : un débit de 4291 authentifications par seconde, et un temps de réponse de 2.195 ms. Si on regarde la charge sur le serveur d'annuaire, on ne constate plus d'écritures sur disque.</p> <pre><code>------------------------------------------------------------------------------ Throughput Response Time (ops/second) (milliseconds) recent average recent average 99.9% 99.99% 99.999% err/sec bind time % ------------------------------------------------------------------------------ 3988.3 3994.8 2.514 2.514 23.066 163.522 167.640 0.0 42.6 .../... 4628.0 4525.7 2.159 2.206 18.978 28.433 158.819 0.0 42.9 4327.2 4510.4 2.219 2.207 19.051 28.221 158.819 0.0 43.0 1450.9 4291.0 1.721 2.195 18.968 28.071 158.406 0.0 42.1 </code></pre><h2>Conclusion</h2> <p>Si l'impact du suivi de la date de dernière connexion n'est pas anodin, surtout dans le cas d'un test, en situation réelle, l'impact peut être relativement négligeable, notamment si les authentifications se font au fil de l'eau.</p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mar 19/12/2017 - 10:42</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/index.php/tags/ldap" hreflang="fr">ldap</a></div> <div class="field__item"><a href="/index.php/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Tue, 19 Dec 2017 09:42:42 +0000 vincentl 187 at https://www.vincentliefooghe.net OpenDS / OpenDJ - Problème de recherche "Unindexed search" https://www.vincentliefooghe.net/index.php/content/opends-opendj-probl%C3%A8me-recherche-unindexed-search <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">OpenDS / OpenDJ - Problème de recherche &quot;Unindexed search&quot;</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Suite à l'installation d'une instance OpenDS 2.3 sur une pré-production, sur RHEL 7 et java 1.6, un utilisateur se plaignait de ne plus pouvoir faire fonctionner son application.</p> <p>Lorsqu'il lançait sa recherche, il n'avait aucun résultat, mais un message d'erreur :</p> <pre>SEARCH operation failed Result Code: 50 (Insufficient Access Rights) Additional Information: You do not have sufficient privileges to perform an unindexed search </pre><p>La résolution du problème a pris quelques heures, le temps d'écumer le guide d'administration (plutôt complet) et les différents sites internet (dont celui de <a href="https://ludopoitou.com">Ludovic Poitou</a>, toujours très utile).</p> <p>La requête de base est la suivante :</p> <ul><li>Scope : wholeSubTree</li> <li>Base ou=site,ou=p1,ou=repository,o=rootSuffix</li> <li>Filter : (id=*).</li> </ul><p>Sachant qu'il y a 9400 objets dans l'ou=site, et que l'attribut <em>id</em> est le RDN de l'objet, tous les objets ont donc un id.</p> <h2>Debug de l'utilisation des requêtes</h2> <p>Le blog de Ludovic Poitou comprenait un article qui parlait des indexes dans OpenDJ (très compatible avec OpenDS), et notamment un attribut opérationnel <em>debugsearchindex</em> qui permet d'avoir les comportement de l'annuaire par rapport aux index.</p> <p>Exemple :</p> <pre>ldapsearch -p 25389 -D 'cn=directory manager' -w password -s one -b ou=site,ou=p1,ou=repository,o=rootSuffix '(id=*)' debugsearchindex dn: cn=debugsearch debugsearchindex: filter=(id=*)[NOT-INDEXED] scope=singleLevel[LIMIT-EXCEEDED:94 17] final=[NOT-INDEXED]</pre><p>L'attribut n'est pas indexé. On va donc ajouter un index, de type substring.</p> <h2>Création d'un index</h2> <pre>dsconfig create-local-db-index --port 4444 --hostname localhost --bindDN "cn=Directory Manager" \ --bindPassword password --backend-name userRoot \ --index-name id --set index-type:substring \ --trustAll --no-prompt</pre><p>Puis on lance le <em>rebuild-index</em></p> <pre>rebuild-index --port 4444 -h localhost -D "cn=directory manager" -w password --baseDN o=rootSuffix --index id --start 0 --trustAll </pre><p>A ce stade, si on lance la même requête, on a toujours le même souci.</p> <p>Par contre, avec un sous-ensemble, ça fonctionne :</p> <pre>ldapsearch -p 25389 -D 'cn=directory manager' -w password -s one -b ou=site,ou=p1,ou=repository,o=rootSuffix '(id=ne*)' debugsearchindex dn: cn=debugsearch debugsearchindex: filter=(id=ne*)[INDEX:id.substring][COUNT:76] scope=singleLeve l[LIMIT-EXCEEDED:9417] final=[COUNT:76]</pre><p><strong>Note</strong> : la recherche en (id=*) nécessite un index de type présence. Il faut donc créer un index de type substring ET presence.</p> <p>Après avoir faire la création et le rebuilt, on peut vérifier les index :</p> <pre>bin/dbtest list-index-status -b "o=rootSuffix" -n userRoot Index Name Index Type JE Database Name Index Status ---------------------------------------------------------------------------------------- id2children Index o_rootSuffix_id2children true id2subtree Index o_rootSuffix_id2subtree true uid.equality Index o_rootSuffix_uid.equality true id.presence Index o_rootSuffix_id.presence true id.substring Index o_rootSuffix_id.substring true </pre><p>Cependant, la recherche sur id=* ne fonctionne toujours pas avec un compte "normal"</p> <pre>bin/ldapsearch -p 25389 -D 'cn=directory manager' -w password -s one -b ou=site,ou=p1,ou=repository,o=rootSuffix '(id=*)' debugsearchindex dn: cn=debugsearch debugsearchindex: filter=(id=*)[INDEX:id.presence][LIMIT-EXCEEDED] scope=singleL evel[LIMIT-EXCEEDED:9417] final=[LIMIT-EXCEEDED:9417]</pre><h2>Changement de la limitation sur les index</h2> <p>Il faut alors jouer avec la propriété  <em>index-entry-limit</em>, qui spécifie le nombre maximum des entrées garder dans un index. Dans notre cas, sachant qu'on a actuellement 9400 entrées de type site, et d'autres objets qui ont également un attribut id, on va fixer la valeur à 12 000.</p> <pre>bin/dsconfig set-local-db-index-prop --port 4444 --hostname localhost --bindDN "cn=Directory Manager" \ --bindPassword password --backend-name userRoot \ --trustAll --no-prompt \ --index-name id \ --set index-entry-limit:12000</pre><p><br />Après avoir lancé le <em>rebuild</em>,</p> <pre>bin/ldapsearch -p 25389 -D 'cn=directory manager' -w password -s one -b ou=site,ou=p1,ou=repository,o=rootSuffix '(id=*)' debugsearchindex dn: cn=debugsearch debugsearchindex: filter=(id=*)[INDEX:id.presence][COUNT:10084] scope=singleLeve l[LIMIT-EXCEEDED:9417] final=[COUNT:10084] </pre><p> </p> <p>A ce niveau, la recherche fonctionne, mais on se heurte à une autre limite :</p> <pre>SEARCH operation failed Result Code: 4 (Size Limit Exceeded) Additional Information: This search operation has sent the maximum of 1000 entries to the client</pre><h2>Modification des limites du compte</h2> <p>Par défaut, on a des limites sur le nombre de résultats retournés :</p> <ul><li>ds-rlim-lookthrough-limit : 5000</li> <li>ds-rlim-size-limit : 1000</li> </ul><p>Il faut donc modifier ces valeurs. Par exemple via un fichier LDIF :</p> <pre>dn: cn=VliPre, ou=account, ou=security, o=rooutSuffix changetype:modify add: ds-rlim-size-limit ds-rlim-size-limit: 15000 - add: ds-rlim-lookthrough-limit ds-rlim-lookthrough-limit: 15000 </pre><p><br />Après toutes ces modifications, le compte peut bien récupérer toutes les entrées.</p> <p>Par contre, on peut se poser la question sur l'intérêt de récupérer des milliers d'entrées.</p> <h2>Désactivation globale du privilège</h2> <p>En derner recours, il est possible de désactiver globalement le privilège <em>unindexed-search</em>, en passant par <em>ds-config</em>.</p> <p>On peut voir configuration en cours :</p> <pre>/opt/OpenDS-2.3.0/bin/dsconfig get-global-configuration-prop \ --port 4444 --hostname localhost --trustAll --bindDN "cn=Directory Manager" --bindPassword password --no-prompt Property : Value(s) --------------------------------------:------------------------ bind-with-dn-requires-password : true default-password-policy : Default Password Policy disabled-privilege : - entry-cache-preload : false etime-resolution : milliseconds idle-time-limit : 0 ms lookthrough-limit : 5000 max-allowed-client-connections : 0 proxied-authorization-identity-mapper : Exact Match reject-unauthenticated-requests : false return-bind-error-messages : false save-config-on-successful-startup : true size-limit : 1000 smtp-server : - time-limit : 1 m workflow-configuration-mode : auto writability-mode : enabled</pre><p><br />Il est possible de modifier la valeur avec ds-config :</p> <pre>/opt/OpenDS-2.3.0/bin/dsconfig set-global-configuration-prop \ --port 4444 --hostname localhost --trustAll --bindDN "cn=Directory Manager" --bindPassword password --no-prompt \ --set disabled-privilege:unindexed-search </pre><p><br />Ceci supprimer les avertissements et erreurs, au détriment des performances, puisque le paramétrage autorise n'importe qui à faire des recherches non indexées.</p> <p>On peut voir la nouvelle configuration :</p> <pre>/opt/OpenDS-2.3.0/bin/dsconfig get-global-configuration-prop \ --port 4444 --hostname localhost --trustAll --bindDN "cn=Directory Manager" --bindPassword password --no-prompt Property : Value(s) --------------------------------------:------------------------ bind-with-dn-requires-password : true default-password-policy : Default Password Policy disabled-privilege : <strong>unindexed-search</strong> entry-cache-preload : false etime-resolution : milliseconds idle-time-limit : 0 ms</pre><p><br /> </p> <p> </p> <p> </p> <p> </p> <p><br /> </p> <p> </p> <p> </p> <p> </p> <p> </p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2017-08-21T15:46:07+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">lun 21/08/2017 - 17:46</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/index.php/tags/index" hreflang="fr">index</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Mon, 21 Aug 2017 15:46:07 +0000 vincentl 180 at https://www.vincentliefooghe.net OpenDJ : personnalisation du schéma https://www.vincentliefooghe.net/index.php/content/opendj-personnalisation-du-sch%C3%A9ma <span class="field field--name-title field--type-string field--label-hidden">OpenDJ : personnalisation du schéma</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Il est d'usage courant de personnaliser le schéma de données, en ajoutant des attributs et des classes d'objets spécifiques au client.</p> <p>OpenDJ permet bien évidemment de définir son propre schéma de données. La déclaration des attributs et classes d'objets est faite dans différents fichiers LDIF, chargés au démarrage de l'instance, et qui se trouvent dans <code>$DJHOME/config/schema</code>.<br />Par défaut, après l'installation, on y trouve une quinzaine de fichiers:</p> <pre>cd $DJHOME ls config/schema/ 00-core.ldif 03-changelog.ldif 03-rfc2739.ldif 03-rfc3712.ldif 05-rfc4876.ldif 06-compat.ldif 01-pwpolicy.ldif 03-rfc2713.ldif 03-rfc2926.ldif 03-uddiv3.ldif 05-samba.ldif 02-config.ldif 03-rfc2714.ldif 03-rfc3112.ldif 04-rfc2307bis.ldif 05-solaris.ldif </pre><p>Les classes d'objets usuelles (organizationalUnit, inetOrgPerson, groupOfNames, etc.) sont définies dans le fichier 00-core.ldif.</p> <p>Pour ajouter des attributs ou classes d'objets spécifiques, on dispose de plusieurs options :</p> <ul><li>Ajouter un fichier <code>99-user.ldif</code> dans le répertoire <code>config/schema</code></li> <li>Utiliser <em>ldapmodify</em> pour ajouter le contenu d'un fichier ldif</li> <li>Utiliser la console</li> </ul><p>Imaginons que nous voulions ajouter une classe auxiliaire <em>customPerson</em>, qui contiendra les attributs :</p> <ul><li>customAccesWeb : flag utilisé par un proxy pour donner ou non l'accès Web. Mono valeur</li> <li>customStartDate : date de début de contrat</li> <li>customEndDate : date de fin de contrat</li> <li>customManagerID : ID / matricule du manager</li> </ul><h2>Modification via le fichier 99-user.ldif</h2> <p>Cette modification doit se faire lorsque l'annuaire est arrêté, puisque les fichiers sont chargés au démarrage de l'instance.<br />On va créer un fichier <code>$DJHOME/config/schema/99-user.ldif</code>, qui contient :</p> <pre>dn: cn=schema objectClass: top objectClass: ldapSubentry objectClass: subschema cn: schema attributeTypes: ( customStartDate-oid NAME 'customStartDate' DESC 'Date de debut de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) attributeTypes: ( customManagerID-oid NAME 'customManagerID' DESC 'ID du manager' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) attributeTypes: ( customAccesWeb-oid NAME 'customAccesWeb' DESC 'Acces Web via Proxy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) attributeTypes: ( customEndDate-oid NAME 'customEndDate' DESC 'Date de fin de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) objectClasses: ( customPerson-oid NAME 'customPerson' DESC 'Person custom' SUP top AUXILIARY MAY ( customAccesWeb $ customStartDate $ customEndDate $ customManagerID) X-ORIGIN 'user defined' ) </pre><p>Une fois l'instance OpenDJ démarrée, on peut vérifier que la nouvelle classe d'objet est créée, en interrogeant la base <em>cn=schema</em> :</p> <pre>$DJHOME/bin/ldapsearch -D "cn=Directory Manager" -w secret -h localhost -p 1389 -b cn=schema -s base "objectclass=ldapSubentry" objectclasses </pre><p><strong>Note</strong> : la commande ci-dessus récupère toutes les classes d'objet. Il n'est pas possible de filtrer directement sur la classe qui nous intéresse.</p> <h2>Modification via ldapmodify</h2> <p>Avec cette option, on va créer un fichier LDIF, qui contient des instructions de modification du schéma. Par exemple :</p> <pre>dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( customAccesWeb-oid NAME 'customAccesWeb' DESC 'Acces Web via Proxy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( customStartDate-oid NAME 'customStartDate' DESC 'Date de debut de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( customEndDate-oid NAME 'customEndDate' DESC 'Date de fin de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( customManagerID-oid NAME 'customManagerID' DESC 'ID du manager' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) dn: cn=schema changetype: modify add: objectClasses objectClasses: ( customPerson-oid NAME 'customPerson' DESC 'Person custom' SUP top AUXILIARY MAY ( customAccesWeb $ customStartDate $ customEndDate $ customManagerID) X-ORIGIN 'user defined' ) </pre><p><strong>Note</strong> : on utilise ici des OID alphabétiques (tel que customPerson-oid). Si on veut utiliser des "vrais" OID, on peut les déclarer sur le site de l'IANA (<a href="http://www.iana.org/assignments/enterprise-numbers/enterprise-numbers">http://www.iana.org/assignments/enterprise-numbers/enterprise-numbers</a>), ou utiliser une plage d'adresse propre, afin d'avoir des OID plus structurés. La tranche <em>1.3.6.1.4.1</em> est réservée aux codes privés pour les entreprises. On peut ensuite décliner les numéros par typologie. Par exemple :</p> <ul><li>1.3.6.1.4.36733 : Forgerock</li> <li>1.3.6.1.4.XXXX : Société XX</li> <li>1.3.6.1.4.XXXX.1 : Schéma LDAP Société XX</li> <li>1.3.6.1.4.XXXX.1.1 : Attributs du schéma LDAP Société XX</li> <li>1.3.6.1.4.XXXX.1.2 : Classes d'objets du schéma LDAP Société XX</li> </ul><p>Dans ce schéma de numérotation, on aurait donc</p> <pre>dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( 1.3.6.1.4.XXXX.1.1.1 NAME 'customAccesWeb' DESC 'Acces Web via Proxy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( 1.3.6.1.4.XXXX.1.1.2 NAME 'customStartDate' DESC 'Date de debut de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) dn: cn=schema changetype: modify add: objectClasses objectClasses: ( 1.3.6.1.4.XXXX.1.2.1 NAME 'customPerson' DESC 'Person custom' SUP top AUXILIARY MAY ( customAccesWeb $ customStartDate $ customEndDate $ customManagerID) X-ORIGIN 'user defined' ) </pre><p>La modification du schéma se fait ensuite via une commande <em>ldapmodify</em> :</p> <pre>$DJHOME/bin/ldapmodify -h {host} -p {port} -D {bindDN} -w {password} -f {path to ldif} </pre><p>Par exemple :</p> <pre>bin/ldapmodify -f ldif/customPerson.ldif -D "cn=Directory Manager" -w secret -h localhost -p 1389 -c </pre><p>On utilise ici le port LDAP (1389 dans notre exemple) car il s'agit bien d'opérations LDAP et pas d'une opération de configuration de OpenDJ.</p> <p>On peut vérifier dans le répertoire <code>$DJHOME/config/schema</code> qu'il existe maintenant un fichier <code>99-user.ldif</code> :</p> <pre>cat $DJHOME/config/schema/99-user.ldif dn: cn=schema objectClass: top objectClass: ldapSubentry objectClass: subschema cn: schema attributeTypes: ( customStartDate-oid NAME 'customStartDate' DESC 'Date de debut de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) attributeTypes: ( customManagerID-oid NAME 'customManagerID' DESC 'ID du manager' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) attributeTypes: ( customAccesWeb-oid NAME 'customAccesWeb' DESC 'Acces Web via Proxy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'user defined' ) attributeTypes: ( customEndDate-oid NAME 'customEndDate' DESC 'Date de fin de contrat' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'user defined' ) objectClasses: ( customPerson-oid NAME 'customPerson' DESC 'Person custom' SUP top AUXILIARY MAY ( customAccesWeb $ customStartDate $ customEndDate $ customManagerID) X-ORIGIN 'user defined' ) modifiersName: cn=Directory Manager,cn=Root DNs,cn=config modifyTimestamp: 20150702081653Z </pre><h2>Modification par la console</h2> <p>Avec OpenDJ, on peut bien évidemment utiliser la console d'administration pour réaliser ces modifications.</p> <p>Une fois connecté, choisir Schéma / Gérer le schéma :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_011.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_011.png&quot;}" role="button" title="Forgerock_011.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_011.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_011.png?itok=IVQ_tm9g" width="466" height="480" alt="Forgerock_011.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On peut alors choisir de gérer les attributs ou les classes d'objets. On peut créer un nouvel attribut ou une nouvelle classe d'objet avec un clic droit :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_013.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_013.png&quot;}" role="button" title="Forgerock_013.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_013.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_013.png?itok=YyLglBf8" width="480" height="315" alt="Forgerock_013.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>La fenêtre de saisie permet de rentrer les informations de base : nom de l'attribut, OID, description et type. Mais elle présente également d'autres options : type (mono / Multi-valué), attribut parent, alias, fichier de définition, Matching Rules.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_015.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_015.png&quot;}" role="button" title="Forgerock_015.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_015.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_015.png?itok=9sflF5nK" width="401" height="480" alt="Forgerock_015.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Cerise sur le gateau : lorsque l'on confirme, la console affiche l'équivalent de la commande utilisée en ligne de commande :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_016.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_016.png&quot;}" role="button" title="Forgerock_016.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_016.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_016.png?itok=k8OkUOko" width="480" height="362" alt="Forgerock_016.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>L'ajout d'une classe d'objet se faire de la même manière. Ici aussi le formulaire permet de saisie quelques options, telles que le fichier de configuration ou le type de classe d'objet (structurelle / auxiliaire). On peut choisir quels sont les attributs portés par la classe d'objet.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_018.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_018.png&quot;}" role="button" title="Forgerock_018.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_018.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_018.png?itok=T8RYDc5v" width="363" height="480" alt="Forgerock_018.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Au final, on a un nouvel attribut et une nouvelle classe d'objet :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_019.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_019.png&quot;}" role="button" title="Forgerock_019.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_019.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_019.png?itok=wOFjqRs7" width="480" height="336" alt="Forgerock_019.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <h2>Références</h2> <p>Guide d'administration OpenDJ / Forgerock : <a href="https://backstage.forgerock.com/#!/docs/opendj/2.6.0/admin-guide#chap-schema">https://backstage.forgerock.com/#!/docs/opendj/2.6.0/admin-guide#chap-s…</a></p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mar 18/08/2015 - 14:03</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Tue, 18 Aug 2015 12:03:24 +0000 vincentl 137 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/index.php/content/opendj-personnalisation-du-sch%C3%A9ma#comments OpenDJ : ajout d'un Root Suffix https://www.vincentliefooghe.net/index.php/content/opendj-ajout-dun-root-suffix <span class="field field--name-title field--type-string field--label-hidden">OpenDJ : ajout d&#039;un Root Suffix</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>L'ajout d'un <em>Root Suffix</em> (racine d'un arbre LDAP) peut se faire via la console graphique, mais aussi en ligne de commande.</p> <p>On peut vouloir ajouter un <em>backend</em> spécifique, ce qui permettra de gérer la réplication différemment pour ce suffixe, ou ajouter le suffixe dans un <em>backend</em> existant.</p> <h2>En ligne de commande</h2> <p>On va utiliser la commande <em>dsconfig</em>, qui gère la configuration de l'annuaire.</p> <h3>Avec ajout d'un nouveau backend</h3> <pre>/opt/opendj/bin/dsconfig create-backend --backend-name hebinweb --type local-db --hostName opendj \ --port 4444 --set base-dn:"o=hebinweb" --set enabled:true \ --bindDN "cn=Directory Manager" --bindPassword secret --noPropertiesFile --trustAll --no-prompt </pre><h3>Ajout à un backend existant</h3> <pre>/opt/opendj/bin/dsconfig set-backend-prop --backend-name userRoot --add base-dn:o=hebinweb \ --hostname localhost --port 4444 --bindDN "cn=Directory Manager" --bindPassword secret \ --trustAll --noPropertiesFile --no-prompt </pre><h2>Via la console graphique</h2> <p>OpenDJ fournit une console graphique (<em>control panel</em>) qui permet de se connecter à différentes instances OpenDJ, locales ou distantes.</p> <p>On peut donc réaliser la même opération via la console. Une fois connecté, on sélectionne "Nouveau DN de base..." :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_001.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_001.png&quot;}" role="button" title="Forgerock_001.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_001.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_001.png?itok=GY0zqzVG" width="480" height="347" alt="Forgerock_001.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>Dans l'écran suivant, on peut alors choisir l'un des backends existant ou en créer un nouveau :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_002.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_002.png&quot;}" role="button" title="Forgerock_002.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_002.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_002.png?itok=3AvNAjI2" width="480" height="331" alt="Forgerock_002.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_003.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_003.png&quot;}" role="button" title="Forgerock_003.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_003.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_003.png?itok=7PLlv0y6" width="480" height="338" alt="Forgerock_003.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p> </p> <p>On arrive ensuite à l'écran de synthèse / confirmation de la création du nouveau DN de base.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_004.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_004.png&quot;}" role="button" title="Forgerock_004.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_004.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_004.png?itok=HY_5cddZ" width="480" height="265" alt="Forgerock_004.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p> </p> <p>Et dans l'écran principal, on peut voir la liste  des DN de base et de leur backend.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/Forgerock_005.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Forgerock_005.png&quot;}" role="button" title="Forgerock_005.png" data-colorbox-gallery="gallery-all-H0GIfVL82W4" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_005.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_005.png?itok=DipUgdjH" width="480" height="468" alt="Forgerock_005.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <p>On pourra ensuite charger les entrées dans l'annuaire, sur ces différents Root Suffix / Base DN.</p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/index.php/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">ven 26/06/2015 - 17:56</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/index.php/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/index.php/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/index.php/tags/opendj" hreflang="fr">opendj</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Fri, 26 Jun 2015 15:56:25 +0000 vincentl 136 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/index.php/content/opendj-ajout-dun-root-suffix#comments