openidm https://www.vincentliefooghe.net/index.php/ fr OpenIDM - Sécuriser un Connecteur Database Table https://www.vincentliefooghe.net/index.php/content/openidm-s%C3%A9curiser-un-connecteur-database-table <span class="field field--name-title field--type-string field--label-hidden">OpenIDM - Sécuriser un Connecteur Database Table</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Dans un projet client qui utilise IDM 7 (après une montée de version OpenIDM 3.1 vers IDM 7 qui s'est plutôt bien passée), nous avons mis en place la gestion du cycle de vie et notamment la suppression automatique de comptes 30 jours après la fin de contrat, comme ce que l'on voit souvent.</p> <p>Il a été décidé d'archiver quelques données des utilisateurs, histoire d'avoir un peu de traces.</p> <p>Pour ce faire nous avons mis en place un connecteur Database Table, qui pointe sur une table d'une base PostgreSQL. La base utilisée est la même que celle qui héberge le <em>repository</em> IDM.</p> <p>Tout fonctionnait correctement, jusqu'au moment où une insertion dans la table est tombée en erreur.</p> <p>Le message d'erreur :</p> <pre> [122] janv. 07, 2021 9:06:00.069 AM org.identityconnectors.framework.impl.api.local.operations.CreateImpl create GRAVE: buildSelectBasedAttributeInfo in SQL: 'SELECT * FROM openidm.archive_managed_user WHERE objectid IS NULL' org.postgresql.util.PSQLException: FATAL: terminating connection due to administrator command at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2532) at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2267) [122] janv. 07, 2021 9:06:00.071 AM org.apache.tomcat.jdbc.pool.PooledConnection clearWarnings AVERTISSEMENT: Unable to clear Warnings, connection will be closed. org.postgresql.util.PSQLException: This connection has been closed. at org.postgresql.jdbc.PgConnection.checkClosed(PgConnection.java:865) at org.postgresql.jdbc.PgConnection.clearWarnings(PgConnection.java:759) at org.apache.tomcat.jdbc.pool.PooledConnection.clearWarnings(PooledConnection.java:837) at org.apache.tomcat.jdbc.pool.ConnectionPool.returnConnection(ConnectionPool.java:977) [122] janv. 07, 2021 9:06:00.073 AM org.forgerock.openidm.quartz.SchedulerServiceJob execute AVERTISSEMENT: Scheduled service "scheduler-service-group.delete" invocation reported failure: org.forgerock.json.resource.ForbiddenException: {code=500, reason=Internal Server Error, message=Operation CREATE failed with ConnectorException on system object} org.forgerock.openidm.quartz.ExecutionException: org.forgerock.json.resource.ForbiddenException: {code=500, reason=Internal Server Error, message=Operation CREATE failed with ConnectorException on system object} at org.forgerock.openidm.script.impl.ScriptRegistryService.execute(ScriptRegistryService.java:772) at org.forgerock.openidm.quartz.SchedulerServiceJob.execute(SchedulerServiceJob.java:123)</pre><p> </p> <h2>Analyse de la cause</h2> <p>En regardant dans les logs nous nous sommes aperçus que la base était indisponible périodiquement, pour une sauvegarde <em>offline</em>.</p> <p>Autant le "<em>moteur</em>" IDM était capable de reprendre son activité une fois la sauvegarde terminée et la base redémarrée, autant le connecteur n'arrivait pas à relancer une connexion.</p> <h2>Résolution</h2> <p>Après différentes recherches sur le Web et l'ouverture d'un ticket "How do I ? " chez Forgerock, j'ai pu modifier le fichier de configuration <em>provisioner.openicf-archiveDB.json</em> pour y modifier les paramètres suivants :</p> <ul> <li>"validationInterval" : "30000"  (permet de limiter la fréquence de validation)</li> <li>"validationQueryTimeout" : "30" (time-out pour les requêtes de validation)</li> <li>"validationQuery" : "SELECT 1 FROM archive_managed_user" (requête SQL utilisée pour la validation)</li> <li>"testOnConnect" : true (permet de valider avant la connection)</li> <li>"testOnBorrow" : true (permet de valider avant d'utiliser une connection dans le <em>pool</em>)</li> </ul> <p>Ce sont surtout les paramètres <strong>validationQuery</strong> et <strong>testOnBorrow</strong> qui permettent de gérer les cas de déconnexion.</p> <p>Une fois la nouvelle configuration mise en place, le connecteur devient <em>fault-tolerant</em> et peut reprendre son activité même après une perte de connexion à la base de données.</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">jeu 07/01/2021 - 09:54</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/taxonomy/term/3" hreflang="fr">openidm</a></div> <div class="field__item"><a href="/index.php/tags/connecteur" hreflang="fr">connecteur</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=209&amp;2=comment_node_book&amp;3=comment_node_book" token="7WaxU_wvuZ5r5sBmYS8TtoL5QqM9MAXmAWnuTkMTqFc"></drupal-render-placeholder> </section> Thu, 07 Jan 2021 08:54:49 +0000 vincentl 209 at https://www.vincentliefooghe.net Connexion OpenIDM / AD SSL https://www.vincentliefooghe.net/index.php/content/connexion-openidm-ad-ssl <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Connexion OpenIDM / AD SSL </span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p><em>De l'importance d'utiliser un nom de serveur correspondant au CN du certificat...</em></p> <h2>Contexte</h2> <p>Afin de pouvoir tester la connexion d'un OpenIDM sur un serveur AD (et par la suite la mise en place du plugin de synchronisation de mot de passe) j'ai mis en place une maquette simple avec :</p> <ul> <li>un serveur OpenIDM sous CentOS</li> <li>un serveur AD sous Windows 2008R2</li> </ul> <p>J'ai mis en place un certificat sur le serveur AD, qui est aussi le contrôleur de domaine principal, avec un certificat qu'il a généré.</p> <p>J'ai importé le certificat dans le Keystore OpenIDM, comme pour toute connexion sécurisée.</p> <h2>Problème</h2> <p>Mais cependant, impossible d'avoir une connexion opérationnelle. La connexion en LDAPS ne fonctionne pas (port 636 / ssl = "true"), alors qu'elle est opérationnelle en LDAP (port 389 / ssl="false")</p> <p>Au démarrage, on trouve ceci dans les logs :</p> <pre>SEVERE: OpenICF connector test of SystemIdentifier{ uri='system/AD/'} failed! org.identityconnectors.framework.common.exceptions.ConnectionFailedException: javax.naming.CommunicationException: mytest-dc.local:636 [Root exception is java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)] </pre><p>Même chose en testant via une requête REST :</p> <pre>http://engine.local:8180/openidm/system/AD/?_action=test Caused by: javax.naming.CommunicationException: mytest-dc.local:636 [Root exception is java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)] </pre><h2>Cause et résolution</h2> <p>Au final, il s'agissait d'un problème de nom DNS. En effet, le serveur AD a son propre nom DNS, et ce n'est pas celui que j'utilisais dans ma connexion (mytest-dc.local).</p> <p>Les logs me donnaient bien une piste :</p> <pre>WARNING: Resource exception: 500 Internal Server Error: "javax.naming.CommunicationException: simple bind failed: lyreco-dc.local:636 [Root exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching lyreco-dc.local found.]" </pre><p>J'ai donc modifié le fichier <em>conf/boot/boot.properties</em> pour positionner le nom de machine égal au CN du certificat du serveur, que l'on peut récupérer avec la commande suivante :</p> <pre>openssl x509 -in adldaps.pem -noout -text |grep Subject Subject: CN=<strong>WIN-RLQ30AF9URF.group.id-num.com</strong> Subject Public Key Info: X509v3 Subject Key Identifier: X509v3 Subject Alternative Name:</pre><p>Une fois le paramétrage du nom effectué, et après avoir modifié mon fichier /etc/hosts pour que mon serveur OpenIDM arrive à faire le lien entre l'adresse IP et le nom, tout est allé beaucoup mieux.</p> <p>Pour que la modification soit prise en compte, il a fallu redémarrer OpenIDM (puisque mon paramétrage se trouve dans le fichier boot.properties).</p> <p>Il a également fallu que je passe par la console d'admin, et que je valide la connexion AD pour que cela soit opérant.</p> <p> </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="2019-11-11T14:17:56+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">lun 11/11/2019 - 15:17</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/taxonomy/term/3" hreflang="fr">openidm</a></div> <div class="field__item"><a href="/index.php/tags/active-directory" hreflang="fr">active directory</a></div> <div class="field__item"><a href="/index.php/tags/ssl" hreflang="fr">ssl</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Mon, 11 Nov 2019 14:17:56 +0000 vincentl 199 at https://www.vincentliefooghe.net Activation LDAPS sur Active Directory https://www.vincentliefooghe.net/index.php/content/activation-ldaps-sur-active-directory <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Activation LDAPS sur Active Directory</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Contexte</h2> <p>Lors des interactions en LDAP avec Active Directory, certaines actions nécessitent l’utilisation de LDAPS (LDAP sur SSL) entre le client et Active Directory.</p> <p>Ceci est notamment le cas si l’on veut modifier le mot de passe.</p> <p>Ce document décrit comment activer le LDAPS sur un environnement Active Directory.</p> <h2>Méthodes envisageables</h2> <p>A priori il y a deux méthodes possibles pour activer LDAPS sur un contrôleur de domaine :</p> <ul> <li>Installer un Certificat Racine sur le contrôleur de domaine</li> <li>Utiliser un certificat tiers sur le contrôleur de domaine.</li> </ul> <p>C’est la seconde méthode que nous allons détailler ici.</p> <h2>Procédure</h2> <p>Les étapes de mise en place sont les suivantes :</p> <ul> <li>Demande de certificat</li> <li>Signature de la demande de certificat</li> <li>Import du certificat sur le serveur</li> </ul> <h2>Certificat</h2> <p>Contraintes sur le certificat Le certificat qui sera généré doit respecter certaines contraintes :</p> <ul> <li>Il doit être validé pour l’authentification de server, c’est à dire contenir l’OID d’authentification du serveur (1.3.6.1.5.5.7.3.1)</li> <li>Le CN doit correspondre au FQDN du serveur. Par exemple, si mon serveur s’appelle pdc1.mondomaine.com, on aura CN=pdc1.mondomaine.com</li> </ul> <h3>Demande de certificat</h3> <p>La demande de certificat peut se faire dans une fenêtre de commande sous Windows, avec la commande suivante :</p> <pre>certreq -new request.inf request.req </pre><p>On aura auparavant créé le fichier request.inf contenant les informations suivantes :</p> <pre>;----------------- request.inf ----------------- [Version] Signature="$Windows NT$” [NewRequest] Subject = "CN=pdc1.mondomaine.com,O=IT,C=FR" ; replace with the FQDN of the DC KeySpec = 1 KeyLength = 2048 ; Can be 1024, 2048, 4096, 8192, or 16384. ; Larger key sizes are more secure, but have a greater impact on performance. Exportable = TRUE MachineKeySet = TRUE SMIME = False PrivateKeyArchive = FALSE UserProtected = FALSE UseExistingKeySet = FALSE ProviderName = "Microsoft RSA SChannel Cryptographic Provider" ProviderType = 12 RequestType = PKCS10 KeyUsage = 0xa0 [EnhancedKeyUsageExtension] OID=1.3.6.1.5.5.7.3.1 ; this is for Server Authentication ;----------------------------------------------- </pre><p>Note : les éléments du <em>Subject</em> doivent correspondre à ceux du certificat racine issu de la PKI.</p> <h3>Signature de la demande de certificat</h3> <p>La génération du certificat peut se faire via une commande OpenSSL, à partir du fichier <code>request.req</code> généré à l’étape précédente.<br />Le certificat racine aura été généré auparavant, dans le répertoire <code>/srv/pki/certs</code>. L'arborescence de ce répertoire est la suivante :</p> <pre>cd /srv/pki ls -R .: certs index.txt index.txt.attr newcerts private reqs serial ./certs: ca.crt ./newcerts: ./private: ca.key ./reqs: request.req </pre><p>On va générér le certificat à partir de la requête :</p> <pre>openssl ca -config /srv/pki/openssl.cnf -name CA_default -extensions CA_AD_SERVER -infiles /srv/pki/ca/reqs/request.req </pre><p>Le fichier openssl.cnf contient les lignes suivantes :</p> <pre>[ ca ] default_ca = CA_default [ CA_default ] dir = . certs = $dir/ca/certs new_certs_dir = $dir/ca/newcerts database = $dir/ca/index.txt certificate = $dir/ca/certs/ca.crt serial = $dir/ca/serial private_key = $dir/ca/private/ca.key default_days = 3650 default_md = sha256 preserve = no policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = optional organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ CA_AD_SERVER ] nsComment = "Certificat Serveur AD" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always issuerAltName = issuer:copy basicConstraints = critical,CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment nsCertType = client, server extendedKeyUsage = serverAuth, clientAuth </pre><p>Il faut ensuite extraire les informations « brutes », situées entre <code>-----BEGIN CERTIFICATE-----</code> et <code>-----END CERTIFICATE-----</code>.</p> <p>On va ensuite créer la “chaîne” de certificats, en concaténant le certificat racine :</p> <pre>cd /srv/pki/ca/certs cat dwdc1.crt ca.crt &gt; dwdc1-chain.crt </pre><h3>Intégration du certificat</h3> <p>Les certificats dwdc1-chain.crt et le certificat racine sont ensuite copiés sur le serveur Windows.</p> <p>Le certificat racine doit être intégré (en utilisant la console mmc) dans les autorités de certification racines de confiance.</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/LDAPSonAD_013.png" title="LDAPSonAD_013.png" data-colorbox-gallery="gallery-all-AHYd3gnmtnM" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;LDAPSonAD_013.png&quot;}"><img src="/sites/default/files/styles/large/public/LDAPSonAD_013.png?itok=qeWJmF_T" width="480" height="223" alt="LDAPSonAD_013.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> <p>Le certificat chaîne peut ensuite être intégré via la commande :</p> <pre>certreq -accept dwdc1-chain.crt I</pre><p>On peut vérifier la bonne intégration, dans les certificats personnels.</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/LDAPSonAD_014.png" title="LDAPSonAD_014.png" data-colorbox-gallery="gallery-all-AHYd3gnmtnM" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;LDAPSonAD_014.png&quot;}"><img src="/sites/default/files/styles/large/public/LDAPSonAD_014.png?itok=u-kAjPeE" width="480" height="115" alt="LDAPSonAD_014.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> <p>Il faut alors redémarrer le serveur sur lequel on vient d’installer le certificat.</p> <h3>Vérification</h3> <p>On peut vérifier en lançant <em>ldp.exe</em>, et en tentant une connexion sur le contrôleur de domaine, port 636.</p> <h2>Références</h2> <p>Ce document est basé sur les éléments suivants :</p> <p><a href="http://www.it-sudparis.eu/s2ia/user/procacci/Doc/ldaps-ad/ldaps-ad.html">http://www.it-sudparis.eu/s2ia/user/procacci/Doc/ldaps-ad/ldaps-ad.html</a></p> <p><a href="https://support.microsoft.com/en-us/help/321051/how-to-enable-ldap-over-ssl-with-a-third-party-certification-authority">https://support.microsoft.com/en-us/help/321051/how-to-enable-ldap-over…</a></p> <p><a href="https://www.petri.com/enable-secure-ldap-windows-server-2008-2012-dc">https://www.petri.com/enable-secure-ldap-windows-server-2008-2012-dc</a></p> <p><a href="https://social.technet.microsoft.com/wiki/contents/articles/2980.ldap-over-ssl-ldaps-certificate.aspx">https://social.technet.microsoft.com/wiki/contents/articles/2980.ldap-o…</a></p> <h2>Annexes</h2> <p>Pour plus de détails sur la partie SSL, on pourra se reporter à <a href="https://www.vincentliefooghe.net/content/mémento-openssl">https://www.vincentliefooghe.net/content/mémento-openssl</a></p> <h3>Génération du Certificat Racine</h3> <p>On génère d’abord la clé privée :</p> <pre>openssl genrsa -des3 -out /srv/pki/ca/certs/ca.key 2048</pre><p>Puis le certificat racine :</p> <pre>cd /srv/pki openssl req -new -x509 -days 3650 -key private/ca.key -sha256 -extensions v3_ca -out certs/ca.crt</pre><h3>Ajout du certificat dans OpenIDM</h3> <p>Si on veut activer les échanges sécurisés via SSL, il faut importer les certificats des serveurs distants dans le keystore OpenIDM.</p> <p>On peut récupérer le nom du truststore dans le fichier de configuration (<em>conf/boot/boot.properties</em>). Par défaut, il s’agit de OPENIDM_HOME/security/truststore.</p> <pre>cd /products/openidm/security keytool -import -alias ADLDAPS -file /tmp/ca/certs/dwdc1.crt -keystore truststore</pre><p>Il faut ensuite arrêter / relancer openidm</p> <p>Bien entendu, dans la déclaration du provisioner.openicf.json on va activer le ssl :</p> <pre> "configurationProperties" : { "host" : "&amp;{AD.HostName}", "port" : "&amp;{AD.LdapServerPortSSL}", "ssl" : true, "principal" : "&amp;{AD.DirectoryAdminName}", "credentials" : { "$crypto" : { </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="2017-05-04T15:37:48+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">jeu 04/05/2017 - 17:37</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/autres" hreflang="fr">Autres</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/ssl" hreflang="fr">ssl</a></div> <div class="field__item"><a href="/index.php/tags/openssl" hreflang="fr">openssl</a></div> <div class="field__item"><a href="/index.php/taxonomy/term/3" hreflang="fr">openidm</a></div> <div class="field__item"><a href="/index.php/tags/ldap" hreflang="fr">ldap</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Thu, 04 May 2017 15:37:48 +0000 vincentl 176 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/index.php/content/activation-ldaps-sur-active-directory#comments OpenIDM : purge des tables audit https://www.vincentliefooghe.net/index.php/content/openidm-purge-des-tables-audit <span class="field field--name-title field--type-string field--label-hidden">OpenIDM : purge des tables audit </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 environnement client OpenIDM 3.1 en production depuis plusieurs mois, l'accès à l'écran d'administration des mappings met de plus en plus longtemps à s'afficher.</p> <h3>English Summary</h3> <p>It may help : if the access time to mapping administration form in OpenIDM becomes very slow, then check the numbers of lines in <em>auditrecon</em> table, and delete old records.</p> <h2>Analyse du problème</h2> <p>En regardant les échanges avec le serveur (via la console du navigateur), on voit que l'URL "endpoint/mappingDetails" est celle qui prend le plus de temps.<br />Ce endpoint appelle un script Javascript, <code>./bin/defaults/script/ui/mappingDetails.js</code>, qui lance une requête SQL permettant de récupérer la date de dernière réconciliation, et ce pour chaque <em>mapping</em> :</p> <pre> lastRecon = openidm.query("audit/recon", { "_queryId": "audit-last-recon-for-mapping", "mapping": m.name, "formatted": false }); </pre><p>En regardant dans le fichier <code>conf/repo.jdbc.json</code>, on peut récupérer le détail de la requête :</p> <pre>audit-last-recon-for-mapping" : "SELECT * FROM ${_dbSchema}.auditrecon WHERE entryType = 'start' AND mapping = ${mapping} and reconaction &lt;&gt; 'reconById' ORDER BY activitydate DESC LIMIT 1" </pre><p>C'est cette requête qui pose problème, notamment car la table <em>auditrecon</em> n'a jamais été purgée.</p> <p>Si on regarde le nombre de lignes par type de <em>mapping</em>, on peut avoir une idée de la volumétrie :</p> <pre>select mapping, count(1) from auditrecon group by mapping ; +-------------------------------------+----------+ | mapping | count(1) | +-------------------------------------+----------+ | AdOrganizationalUnit_Officelocation | 3956 | | ldapFunctionnal_Orga | 482874 | +-------------------------------------+----------+ 2 rows in set (3.36 sec) </pre><p>On peut alors tester la requête lancée par le script <code>mappingDetails.js</code> :</p> <pre>SELECT * FROM auditrecon WHERE entryType = 'start' AND mapping = 'ldapFunctionnal_Orga' and reconaction &lt;&gt; 'reconById' ORDER BY activitydate DESC LIMIT 1 ; </pre><p>Le nombre élevé s'explique car il s'agit d'une réconciliation lancée à intervalle régulier (toutes les 15 minutes), pour récupérer des objets de type 'organisation' : départements, fonctions, sections.<br />De ce fait, on arrive rapidement à un nombre élevé de lignes, sachant que chaque réconciliation traite près de 500 lignes, soit 4*24*500 = 48 000 lignes par jour !</p> <p>On peut tenter d'en savoir un peu plus sur la volumétrie. Pour avoir la taille des tables :</p> <pre>SELECT table_name, table_rows as 'Rows #', data_length /1024 as 'Data size KB', index_length/1024 as 'Index size KB' , round( (data_length + index_length) / 1024 / 1024,2 ) as 'Taille MB' FROM information_schema.tables WHERE table_schema = 'openidm' AND table_name like 'audit%'; +---------------+--------+--------------+---------------+-----------+ | table_name | Rows # | Data size KB | Index size KB | Taille MB | +---------------+--------+--------------+---------------+-----------+ | auditaccess | 6153 | 2080.0000 | 2144.0000 | 4.13 | | auditactivity | 843 | 22544.0000 | 1056.0000 | 23.05 | | auditrecon | 449959 | 541952.0000 | 592448.0000 | 1107.81 | | auditsync | 797 | 7696.0000 | 0.0000 | 7.52 | +---------------+--------+--------------+---------------+-----------+ 4 rows in set (0.15 sec) </pre><p><strong>Note</strong> : s'agissant de tables utilisant le moteur InnoDB, le nombre de lignes donnés par cette requête peut varier. Il vaut mieux utiliser un SELECT COUNT pour avoir le nombre réel de lignes. La volumétrie en KB, par contre, semble stable.</p> <h2>Epuration des tables d'audit</h2> <p>Il existe une tâche programmée qui permet de lancer un nettoyage régulier des tables d'audit. Sur une installation OpenIDM 3.1, le fichier de définition se trouve dans <code>samples/schedules/schedule-autoPurgeAuditRecon.json</code> :</p> <pre>{ "enabled" : false, "type" : "cron", "schedule" : "0 0 */12 * * ?", "persisted" : true, "misfirePolicy" : "doNothing", "invokeService" : "script", "invokeContext" : { "script" : { "type" : "text/javascript", "file" : "audit/autoPurgeAuditRecon.js", "input" : { "mappings" : [ "%" ], "purgeType" : "purgeByNumOfReconsToKeep", "numOfRecons" : 1, "intervalUnit" : "minutes", "intervalValue" : 1 } } } } </pre><p>Dans la configuration par défaut, on limite à un nombre fini de réconciliations. Si on veut garder un nombre de jours limité, il faut modifier la définition pour utiliser le type de purge <em>purgeByExpired</em> :</p> <pre>{ "enabled" : true, "type" : "cron", "schedule" : "0 0 22 * * ?", "persisted" : true, "misfirePolicy" : "doNothing", "invokeService" : "script", "invokeContext" : { "script" : { "type" : "text/javascript", "file" : "audit/autoPurgeAuditRecon.js", "input" : { "mappings" : [ "%" ], "purgeType" : "purgeByExpired", "numOfRecons" : 1, "intervalUnit" : "days", "intervalValue" : 30 } } } } </pre><p>Le souci étant dans ce cas que, puisqu'on n'a jamais lancé de purge, la requête tombe en time-out...</p> <p>Dans ce cas, On peut aussi utiliser une méthode plus radicale, consistant à supprimer les lignes dans la table, de la manière suivante :</p> <pre>DELETE FROM auditaccess WHERE activitydate &lt; 'YYYY-MM-DD' ; </pre><p>On peut générer les instructions avec un script shell, qui va calculer la date (ce qui est plus rapide que d'utiliser les fonctions MySQL) :</p> <pre>#!/bin/bash # ----------------------------- # Purge OpenIDM audit database # ----------------------------- # # Please stop openidm first, and there remove felix-cache content before restarting #----------------------------------------------------------------------------------- # Set data retention period here LongTimeAgo=$(date -d 'now -6 months' +'%Y-%m-%d') echo "DELETE FROM auditaccess WHERE activitydate &lt; '$LongTimeAgo' ;" &gt; /tmp/purge.sql echo "DELETE FROM auditactivity WHERE activitydate &lt; '$LongTimeAgo' ;" &gt;&gt; /tmp/purge.sql echo "DELETE FROM auditrecon WHERE activitydate &lt; '$LongTimeAgo' ;" &gt;&gt; /tmp/purge.sql echo "DELETE FROM auditsync WHERE activitydate &lt; '$LongTimeAgo' ;" &gt;&gt; /tmp/purge.sql # Ou utiliser la commande mysql en ligne echo "SELECT table_name, data_length /1024 AS 'Data size KB', index_length/1024 AS 'Index size KB' , round( (data_length + index_length) / 1024 / 1024,2 ) AS 'Taille MB' FROM information_schema.tables WHERE table_schema = 'openidm' and table_name like 'audit%'; " &gt;&gt; /tmp/purge.sql echo "exit" &gt;&gt; /tmp/purge.sql SQLUSER=openidm SQLPWD=openidm SQLDB=openidm DBHOST=db.mydomain.com DBPORT=3306 mysql -h ${DBHOST} -P ${DBPORT} -u ${SQLUSER} -p${SQLPWD} ${SQLDB} &lt; /tmp/purge.sql # # --- End of script # </pre><p>Il ne reste plus qu'à lancer le script shell, de manière réguliere (une fois par semaine par exemple), pour limiter le nombre de lignes dans la table, et retrouver un temps de réponse correct lorsqu'on passe par l'écran de gestion des <em>mappings</em></p> <h2>En conclusion</h2> <p>Si l'accès à la page <em>Mappings</em> de la console d'administration OpenIDM est de plus en plus long, vérifier le nombre de lignes dans la table <em>auditrecon</em>, et lancer régulièrement une purge de cette table, soit via le <em>schedule-autoPurgeAuditRecon</em>, soit directement en SQL.</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">mer 14/12/2016 - 09:31</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/taxonomy/term/3" hreflang="fr">openidm</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/audit" hreflang="fr">audit</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> Wed, 14 Dec 2016 08:31:54 +0000 vincentl 171 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/index.php/content/openidm-purge-des-tables-audit#comments OpenIDM : réduire les logs du scheduler https://www.vincentliefooghe.net/index.php/content/openidm-r%C3%A9duire-les-logs-du-scheduler <span class="field field--name-title field--type-string field--label-hidden">OpenIDM : réduire les logs du scheduler</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item">Chez un client, nous avons activé le niveau de log à INFO par défaut afin d'avoir des traces des opérations, notamment car on travaille sur la base d'un changelog depuis un annuaire LDAP Sun, avec un polling toutes les 10 secondes. Plusieurs providers sont ainsi déclenchés : l'un pour les utilisateurs du LDAP, un autre pour les groupes, et encore un pour les groupes AD.Ceci a pour effet de bord de remplir les logs d'informations peu utiles, du genre : Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" found, invoking. Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" found, invoking. Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" invoke completed successfully. Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" invoke completed successfully. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" found, invoking. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" found, invoking. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" invoke completed successfully. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" invoke completed successfully. Dans le fichier logging.properties, il n'y a pas moyen de spécifier le niveau de log pour le scheduler. En fait, ceci se fait directement dans le fichier de configuration du scheduler, en ajoutant l'option <strong>"invokeLogLevel" : "debug"</strong>Par exemple : { "enabled" : true, "type" : "cron", "persisted" : true, "misfirePolicy" : "fireAndProceed", "schedule" : "0/10 * * * * ?", "concurrentExecution" : false, "invokeService" : "provisioner", "invokeContext" : { "action" : "liveSync", "source" : "system/DSEE/user" }, "invokeLogLevel" : "debug" } Du coup, on gagne en lisibilité dans les logs, et on épargne de l'espace disque, tout en pouvant garder un historique un peu plus long.L'option est présente dans la documentation (Integrator's guide). Mais comme elle n'est pas intégrée dans le fichier <em>logging.properties</em>, elle n'est pas forcément facile à trouver. </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 22/11/2016 - 17:52</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/taxonomy/term/3" hreflang="fr">openidm</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, 22 Nov 2016 16:52:28 +0000 vincentl 168 at https://www.vincentliefooghe.net Erreur de synchronisation de mot de passe AD / OpenIDM 2.1 https://www.vincentliefooghe.net/index.php/content/erreur-synchronisation-mot-passe-ad-openidm-21 <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Erreur de synchronisation de mot de passe AD / OpenIDM 2.1</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Problème</h2> <p>Suite à une mise à jour sur un serveur Windows, le plug-in de synchronisation de mot de passe entre le serveur Active Directory et OpenIDM 2.1 ne fonctionnait plus.</p> <p>La console d'événements Windows était remplie d'erreur, et dans le fichier de logs OPENIDM_HOME/logs/openidm0.log.0, on avait de nombreuses erreurs :</p> <pre>WARNING: javax.net.ssl.SSLException: Unsupported record version Unknown-79.83 WARNING: javax.net.ssl.SSLException: Unsupported record version Unknown-79.83 WARNING: javax.net.ssl.SSLException: Unsupported record version Unknown-79.83 WARNING: javax.net.ssl.SSLException: Unsupported record version Unknown-79.83</pre><p>Après plusieurs tests, il s'avère que cela est du au patch <strong>KB3161639</strong>,  qui est inclus dans les KB3161608 &amp; KB3161606  (Roll-Out de Juin 2016) et KB3172605 &amp; KB3172614 (Juillet 2016).</p> <h2>Cause</h2> <p>Le patch KB3161639  est utilisé pour ajouter de nouvelles suites de chiffrement pour Internet Explorer et Microsoft Edge dans Windows.</p> <p>Le souci est que ceci renforce le niveau de chiffrement, notamment en demandant une longueur de clé Diffie-Hellman supérieure à 1024 bits.</p> <p>Hors, le plug-in de synchronisation de mot de passe AD vers OpenIDM utilise https, et si on tente une connexion SSL on a les éléments suivants :</p> <pre># openssl s_client -connect localhost:8443 CONNECTED(00000003) depth=0 O = OpenIDM Self-Signed Certificate, CN = 1.domain.com verify error:num=18:self signed certificate verify return:1 .../... No client certificate CA names sent <strong>Server Temp Key: DH, 768 bits</strong> --- SSL handshake has read 1529 bytes and written 415 bytes --- New, TLSv1/SSLv3, Cipher is DHE-RSA-AES128-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE</pre><p><br /><br />On constate que la clé Diffie-Hellman ne fait que 768 bits, et n'est donc pas acceptée.</p> <p>Ceci n'est valable que pour un OpenIDM 2.1, tournant sous Jetty 7. Dès qu'on utilise une version supérieure (OpenIDM 3.0, 3.1, 4, etc), le problème n'apparaît pas.</p> <h2>Résolution</h2> <p>Lorsqu'on recherche des méthodes de résolution, celle qui revient le plus souvent est de faire un rollback des patchs. Ce qui n'est pas forcément la meilleure solution.</p> <p>Nous avons trouvé une solution de contournement (voir référence [1]), en modifiant la base de registre. Sur un serveur Windows 2012, il a fallu <strong>ajouter</strong> une clé de registre "Diffie-Hellman", avec la valeur 0000200 :</p> <p><strong>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman]"ClientMinKeyBitLength"=dword:00000200</strong></p> <p>Cette clé de registre permet de baisser la longueur de la clé à 512 bits, au lieu des 1024 par défaut.</p> <p>La modification n'impose pas de redémarrer le serveur.<br /> </p> <h2>Références</h2> <ul> <li>[1] <a href="http://vstepic.blogspot.co.uk/2016/07/kb3161608-kb3161606-replaced-by.html?_sm_au_=iMVD0JQqL1FM1M76">http://vstepic.blogspot.co.uk/2016/07/kb3161608-kb3161606-replaced-by.h…</a></li> <li>[2] <a href="https://support.microsoft.com/en-gb/kb/3161639">https://support.microsoft.com/en-gb/kb/3161639</a></li> </ul> </div> <span rel="sioc:has_creator" 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 property="dc:date dc:created" content="2016-09-01T13:15:22+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">jeu 01/09/2016 - 15:15</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/taxonomy/term/3" hreflang="fr">openidm</a></div> <div class="field__item"><a href="/index.php/tags/ssl" hreflang="fr">ssl</a></div> <div class="field__item"><a href="/index.php/tags/windows" hreflang="fr">windows</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Thu, 01 Sep 2016 13:15:22 +0000 Vincent 162 at https://www.vincentliefooghe.net OpenIDM - Rotation des fichiers d'audit https://www.vincentliefooghe.net/index.php/content/openidm-rotation-des-fichiers-daudit <span class="field field--name-title field--type-string field--label-hidden">OpenIDM - Rotation des fichiers d&#039;audit</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Versions 2.1 à 3.1</h2> <p>Dans  les versions 2.1, 3.0 et 3.1, OpenIDM fournit un script shell qui permet de mettre en place la rotation des fichiers d'audit (OPENIDM_HOME/bin/create-openidm-logrotate.sh).</p> <p>Par contre ce script a 2 inconvénients à mon sens :</p> <ul> <li>si on ne redémarre pas OpenIDM, les fichiers CSV ne sont pas <em>resettés</em>, et on se retrouve donc avec un fichier vide</li> <li>la configuration par défaut compresse tous les fichiers du répertoire, et donc fait du récursif sur les fichiers déjà compressés.</li> </ul> <p>Dans ce cas, on peut vite arriver à avoir généré des centaines de milliers de fichiers sur l'espace d'un mois - c'est ce qui m'est arrivé chez un client.</p> <p>Le fichier de définition des rotations de fichier par défaut contient :</p> <pre>${OPENIDM_HOME}/audit/* { daily missingok rotate 54 compress } </pre><p>Il faut le corriger en :</p> <pre>${OPENIDM_HOME}/audit/*.csv { daily missingok rotate 54 compress } pour éviter de faire tourner et compresser les fichiers déjà existants. </pre><p>On aura donc par exemple :</p> <pre>$ cat /etc/logrotate.d/openidmlogs /products/openidm/audit/*.csv daily missingok rotate 54 compress } </pre><h2>Version 4 et supérieure</h2> <p>Depuis la version 4, le script n'est plus fourni car on peut déclencher la rotation des fichiers d'audit via une commande REST (cf. Integration Guide, § 18.9.1).</p> <p>Par exemple, pour déclencher la rotation du fichier <em>access.csv</em> :</p> <pre>curl \ --cacert self-signed.crt \ --header "X-OpenIDM-Username: openidm-admin" \ --header "X-OpenIDM-Password: openidm-admin" \ --request POST \ "https://localhost:8443/openidm/audit/access?handler=csv&amp;_action=rotate"</pre><p>Il faut bien évidemment répéter la commande pour les fichiers <em>activity.csv</em> et <em>recon.csv</em>.</p> <p> </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">lun 06/06/2016 - 18:14</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/taxonomy/term/3" hreflang="fr">openidm</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/log" hreflang="fr">log</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Mon, 06 Jun 2016 16:14:17 +0000 Vincent 158 at https://www.vincentliefooghe.net OpenIDM - les avantages et la souplesse de l'ouverture https://www.vincentliefooghe.net/index.php/content/openidm-les-avantages-et-la-souplesse-louverture <span class="field field--name-title field--type-string field--label-hidden">OpenIDM - les avantages et la souplesse de l&#039;ouverture</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Une fois n'est pas coutume, cet article ne sera pas (trop) orienté technique, mais fait plutôt suite à un retour d'expérience sur un projet qui se termine, et dans lequel la souplesse de OpenIDM et son côté "boîte à outils" ont permis de faire des choses qui auraient été compliquées à faire avec un autre outil (sachant que la principale solution avec laquelle je peux comparer est IBM ISIM).<br /><strong>Note : ceci s'applique à la version 3.1</strong>. La version 4.0 a de nouvelles fonctionnalités proches de celles que nous avons implémenté, mais n'était pas disponible au démarrage du projet.</p> <p>Je vais tout d'abord poser le contexte du projet et ces spécificités, et par la suite les fonctions qui ont permis de répondre à ces demandes.</p> <h2>Contexte du projet</h2> <h3>Le projet initial</h3> <p>A l'origine, le projet consistait <em>simplement</em> à faire une migration technique à partir de Sun IDM. L'environnement technique était assez courant :</p> <ul> <li>Serveur sous linux</li> <li>Repository sous Oracle de préférence (cluster Exadata)</li> <li>Connecteurs LDAP (2 <em>root Suffix</em> sur le même serveur)</li> <li>Gestion des comptes Active Directory</li> <li>Gestion des boîtes aux lettres Exchange</li> <li>Connecteur SAP "OLO" (On Line Ordering)</li> </ul> <p>Bref, a priori, et vu les fonctions mises en oeuvre par notre société il y a 7 ans (en 2007 / 2008), la solution OpenIDM devait convenir, puisque Forgerock nous précise qu'un connecteur SAP est (ou sera) disponible.</p> <p>Une particularité du client cependant : dans Sun IDM, il gère des "vrais" utilisateurs nominatifs, et des comptes de commerciaux (SFA = Sales Forces Automation) qui sont des comptes génériques, qui gèrent des périmètres géographiques, et peuvent passer d'une personne à une autre.</p> <p>Dans Sun IDM, on a donc deux types d'utilisateurs, avec quasiment les mêmes attributs.</p> <p>Pour la partie IHM, nous avons prévu de réécrire la partie annuaire pages blanches, et d'adapter l'interface de gestion des utilisateurs en ajoutant certains champs. J'ai testé la modification, et ça me semble jouable.</p> <h3>La réalité du projet</h3> <p>Premières réunions de cadrage et d'architecture, et là ça commence à se compliquer...</p> <p>Tout d'abord, nous nous apercevons que le client n'a plus la connaissance de ce qui est en place. Les membres de l'équipe qui ont participé au projet il y a 7 ans sont partis dans d'autres sociétés, et la documentation ne semble plus à jour.<br />Le responsable du lancement de l'appel d'offre chez le client a également posé sa démission, et est parti avant le démarrage du projet.<br />Le chef de projet est assez nouveau dans la société (un an d'ancienneté), avec un rôle d'adminisrateur système Windows, et ne connaît donc pas toutes les particularités mise en place.<br />Nos anciens collègues qui ont mis en place sont soit partis, soit en mission en clientèle et donc difficilement mobilisables.<br />Jusque là, rien de trop grave, j'ai mis la main sur la documentation de l'ancien projet, ainsi que sur le code source des adaptateurs développés. On devrait s'en sortir.</p> <p>Plus embêtant, la première réunion fait également état d'un autre projet d'intranet / réseau social d'entreprise (RSE), qui a plusieurs impacts sur le périmètre de notre projet :</p> <ul> <li>Il faut que chaque personne dispose d'un compte nominatif, pour pouvoir participer / poster en son nom (et pas un compte générique)</li> <li>Du coup, il faut pouvoir lier une identité personnelle avec un ou N comptes commerciaux</li> <li>Et, effet collatéral, notre projet de migration technique devient sur le chemin critique du projet de RSE, qui a une forte visibilité</li> </ul> <p>Au final, on se retrouve avec un schéma des interactions qui ressemble à ça :</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/OpenIDMLyrecoSchema.png" title="OpenIDMLyrecoSchema.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;OpenIDMLyrecoSchema.png&quot;}"><img src="/sites/default/files/styles/large/public/OpenIDMLyrecoSchema.png?itok=IVc9WwUL" width="480" height="444" alt="OpenIDMLyrecoSchema.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>En plus, on va coupler tout cela avec un changement d'annuaire, le client voulant passer de Sun Directory Server vers autre chose, probablement OpenDJ.</p> <p>A première vue, ceci n'arrange pas trop nos affaires, surtout que tout ceci démarre fin mai et que la période de congés arrive, et que nos ressources compétentes sur le sujet IAM sont très limitées. Pour tout dire, je découvre le produit OpenIDM au démarrage du projet.</p> <p>Autre souci : OpenIDM 3.1 ne gère pas (encore) le multi-comptes. A priori la version 4.0 devrait le faire, mais ne sera pas disponible avant la date de mise en production.</p> <p>Bref, le <em>simple projet de migration technique</em> se transforme en <em>projet critique avec un gros aspect fonctionnel</em>.</p> <p>Après réflexion, une fois la galère passée, je me rends compte que nous (le chef de projet et moi-même) aurions du tirer la sonnette d'alarme et négocier un avenant pour le changement de périmètre du projet. Mais le CP était un peu jeune (en fait, c'est son premier projet au forfait en tant que CP), et moi je me pose des questions sur la faisabilité technique.</p> <p>Les aspects techniques qui sont amenés par ces nouveautés :</p> <ul> <li>il faut gérer deux types d'objets OpenIDM : nominatifs (user) et SFA (sfa)</li> <li>l'application de gestion doit être entièrement réécrite de zéro, sans penser à faire évoluer l'IHM OpenIDM</li> </ul> <p>Nous sommes aidés sur les choix de l'architecture à mettre en place par une société partenaire de Forgerock, <a href="http://paradigmo.com/">Paradigmo</a>, qui nous a guidé sur les possibilités du produit dans un premier temps, puis est intervenue sur la compilation du connecteur SAP à partir du code source.</p> <h2>Les choix d'orientation technique</h2> <p>Au final, nous sommes donc partis sur les bases suivantes :</p> <ul> <li>Un objet OpenIDM <em>user</em></li> <li>Un objet OpenIDM <em>sfa</em></li> <li>Le lien entre <em>sfa</em> et <em>user</em> géré via un attribut <em>uniqueIdentifier</em>, propre à chaque <em>user</em> (un numéro de séquence)</li> <li>Une application écrite en Java / Spring Framework / Thymleaf, qui utilise les capacités REST de OpenIDM</li> </ul> <p>Le projet a finalement été mené à terme, avec plus ou moins de retard, du fait des évolutions fonctionnelles non prévues au départ. Cependant, ces besoins spécifiques nous ont appris pas mal de choses intéressantes sur OpenIDM, et prouvé notamment l'intérêt d'un système ouvert. Par "ouvert", je veux parler d'une volonté d'interopérabilité du produit, qui a prouvé son ouverture sur différents points :</p> <ul> <li>la possibiltié de gérer des objets différents</li> <li>l'interface REST permettant d'accéder aux différentes fonctions du produit</li> <li>le connecteur SAP scripté</li> <li>le connecteur PowerShell scripté</li> <li>la possibilité de créer ses <em>endpoints</em> spécifiques</li> </ul> <h2>Modèle d'objets</h2> <p>Dans la version 3.1 OpenIDM, on distingue bien les ressources (qui peuvent être cible ou source pour les comptes), et les objets gérés par OpenIDM (<em>managed items</em>).</p> <p>Autant les données des ressorces sont déclarées dans les fichiers de paramétres (<code>provisioner-XX.json</code>), autant le modèle des objets internes est extensible. Par défaut on ne précise pas le schémam de données qui est utilisé, on peut donc ajouter n'importe quel attribut, puisque la plupart du temps l'objet est stocké comme un objet JSON dans la base de données du <em>repository.</em></p> <p>De même, on peut facilement ajouter un objet managé, ce que nous avons fait pour les objets "sfa". Il suffit de quelques lignes dans le fichier <code>conf/managed.json</code> pour déclarer le nouvel objet. Par exemple :</p> <pre>{ "onDelete" : { "type" : "text/javascript", "file" : "ui/onDelete-user-cleanup.js" }, "onCreate" : { "type" : "text/javascript", "file" : "script/sfa/onCreateOrUpdateSfa.js" }, "onUpdate" : { "type" : "text/javascript", "file" : "script/sfa/onCreateOrUpdateSfa.js" }, "properties" : [ { "encryption" : { "key" : "openidm-sym-default" }, "name" : "securityAnswer", "scope" : "private" }, { "encryption" : { "key" : "openidm-sym-default" }, "name" : "password", "scope" : "private" }, { "type" : "virtual", "onRetrieve" : { "type" : "text/javascript", "rolesPropName" : "roles", "file" : "roles/effectiveRoles.js" }, "name" : "effectiveRoles" }, { "type" : "virtual", "onRetrieve" : { "type" : "text/javascript", "effectiveRolesPropName" : "effectiveRoles", "file" : "roles/effectiveAssignments.js" }, "name" : "effectiveAssignments" } ], "name" : "sfa" }, </pre><p>On définit ainsi un objet <strong>sfa</strong>, qui aura 2 attributs encryptés, et des attributs virtuels (effectiveRoles et effectiveAssignments). On précise également les scripts utilisés lors des opération de création, modification et suppression.<br />Dès lors, on peut accéder aux fonctions OpenIDM via un requête REST sur l'URL <code>http://host.openidm.test:8080/openidm/sfa</code></p> <p> </p> <h2>Connecteur SAP</h2> <p>Dans le cadre du projet, nous devons connecter plusieurs instances SAP. Forgerock propose un connecteur OpenICF, qui dispose d'exemples pour SAP R/3 et SAP HR. La version que nous voulons utiliser n'étant pas encore disponible pour OpenIDM 3.1, nous sommes repartis des sources, et avons compilé le connecteur, avec les librairies SAP JCO.</p> <p>Au final, il s'agit d'un connecteur scripté de type Groovy, qui s'est révélé suffisamment souple pour arriver à nos fins, car l'interaction avec SAP passait par des appels à des RFC spécifiques développées par le client, pour alimenter des tables SAP propres au client.</p> <p>On peut trouver le code source sur GitHub / OpenRock : <a href="https://github.com/OpenRock/OpenICF-sap-connector">https://github.com/OpenRock/OpenICF-sap-connector</a>.<br />Le connecteur a été compilé à partir des sources, via <em>maven</em>. Il faut auparavant récupérer les librairies sapjco. D'après ce que j'en ai vu, les clients SAP peuvent avoir accès à ces librairies.</p> <pre>git clone https://github.com/OpenRock/OpenICF-sap-connector.git mvn install </pre><p>L'intérêt d'un connecteur scripté est de s'adapter à quasiment toutes les situations. Au final, on utilise un script par action :</p> <ul> <li>CreateSAPWebshop.groovy : pour la création des comptes</li> <li>DeleteSAPWebshop.groovy : pour la suppression</li> <li>SchemaSAPWebshop.groovy : définition du schéma. Nous avons laissé le paramétrage par défaut</li> <li>SearchAllSAPWebshop.groovy : liste des comptes SAP</li> <li>SearchSAPWebshop.groovy : recherche / lecture d'un compte</li> <li>TestSAPWebshop.groovy : test du connecteur SAP</li> <li>UpdateSAPWebshop.groovy : mise à jour du compte</li> </ul> <p>La déclaration de l'utilisation des scripts se fait dans le fichier <code>provisioner.openicf-SAP.json</code> :</p> <pre> "createScriptFileName" : "&amp;{launcher.project.location}/script/sap/CreateSAPWebshop.groovy", "deleteScriptFileName" : "&amp;{launcher.project.location}/script/sap/DeleteSAPWebshop.groovy", "schemaScriptFileName" : "&amp;{launcher.project.location}/script/sap/SchemaSAPWebshop.groovy", "searchScriptFileName" : "&amp;{launcher.project.location}/script/sap/SearchSAPWebshop.groovy", "searchAllScriptFileName" : "&amp;{launcher.project.location}/script/sap/SearchAllSAPWebshop.groovy", "testScriptFileName" : "&amp;{launcher.project.location}/script/sap/TestSAPWebshop.groovy", "updateScriptFileName" : "&amp;{launcher.project.location}/script/sap/UpdateSAPWebshop.groovy" </pre><p>Nous avons rencontré quelques soucis dans le paramétrage car le client dispose de plusieurs instances SAP, et que la documentation sur le connecteur était assez évasive sur le sujet. Au final, il s'avère que le paramètre <em>destination</em> doit être unique, et sert comme clé pour OpenIDM. On aura donc par exemple :</p> <pre> "configurationProperties" : { "host" : "p06ci.example.com", "user" : "OPENIDMADMIN", "password" : secret, "client" : "020", "vkorg" : "0016", "destination" : "SAP06", .../... } "_id" : "provisioner.openicf/SAP06", "operationOptions" : { }, "name" : "SAP06", </pre><p>Tout ceci n'étais pas documenté (le connecteur SAP ne sera finalement disponible et validé que pour la version 4). Par contre, le support se montre réactif, et plusieurs fois nous avons pu entrer en contact direct avec l'équipe de développement, dont plusieurs membres sont français, ce qui ne gâche rien...</p> <p> </p> <h2>Connecteur Powershell</h2> <p>Dans la série des connecteurs scriptés, on trouve également le connecteur Powershell. Celui-ci implique l'utilisation du serveur de connecteur .Net, à installer sur un serveur Windows, et qui sert de passerelle entre OpenIDM et le monde Windows.</p> <p>Une fois le serveur de connecteur .Net installé, il faut également extraite l'archive <code>mspowershell-connector-1.4.0.0.zip</code> dans le répertoire du serveur de connecteur.<br />On peut alors déclarer un connecteur Powershell, en créant un fichier <code>conf/provisioner.openicf-powershell.json</code> dans le répertoire du projet. Ce connecteur va préciser quels sont les scripts Powershell à utiliser pour quelles opérations.<br /><strong>Note</strong> : le chemin spécifié pour chaque script est celui correspondant au serveur distant.</p> <p>Dans notre projet, nous avons utilisé le connecteur Powershell pour gérer des boîtes de messagerie Exchange.<br />Plusieurs exemples sont fournis dans les <em>samples</em>, et l'on peut aussi trouver sur le web des exemples de configuration pour Exchange. A ce stade, le mieux est de travailler avec les administrateurs des plates-formes Windows, qui devraient avoir la connaissance du Powershell.<br />Les principaux soucis que nous avons eu étaient causés par des délais de synchronisation entre Exchange et AD, avec des informations qui n'étaient pas encore présentes dans Active Directory lors de la création de la boîte mail.<br />Une évolution future consistera à utiliser le connecteur (ou un autre) pour gérer des boîtes Office 365, en parallèle d'une installation Exchange 'traditionnelle'.</p> <p>Parmi les soucis rencontrés, on peut citer la difficulté à comprendre comment passer les paramètres entre le connecteur et OpenIDM, les problèmes liés à l'appel d'une fonction non assignée (qui propovque des exceptions), etc.<br />Mais au final, le connecteur fonctionne, même s'il n'est pas très rapide.</p> <h2>Interface REST</h2> <p>L'une des particularités du produit - et de toute la "<em>stack</em>" Forgerock, est de proposer une interface REST permettant de piloter et gérer la quasi totalité de leurs solutions. Que ce soit OpenIDM, OpenDJ ou OpenAM, tous exposent une interface permettant d'y accéder via de "<em>simples</em>" requêtes REST / http.</p> <p>Ceci nous a permis de développer plusieurs choses autour du produit :</p> <ul> <li>Une nouvelle interface graphique, suivant la charte du client, et découplée du "moteur" OpenIDM</li> <li>Des sripts d'administration / débogage, écrits pour la plupart en shell linux</li> <li>Des scripts de reprise de données, écrits en PHP</li> </ul> <p> </p> <h3>Interface graphique</h3> <p>Lors de la phase initiale de la réponse à appel d'offres, j'avais testé quelques modifications sur l'interface User proposée par Forgerock. Moyennant quelques adaptations de CSS et de templates, ceci aurait pu être utilisable, dans un environnement proche du standard (un seul type d'objet User par exemple).<br />Le changement fonctionnel induit par l'intranet, et l'ajout d'un objet SFA, nous on forcé à faire d'autres choix, tout en restant sur le même modèle que Forgercok pour les échanges avec le "moteur" OpenIDM : l'utilisation de REST.<br />Par contre, l'application est assez traditionnelle, s'agissant d'une application Java, installée dans un serveur Tomcat. Nous aurions pu faire une application 100% Javascript client (comme celle de Forgerock), mais nos ressources sur le sujet - et celles du client - étaient trop peu nombreuses.</p> <p>Au final, l'application fonctionne, et s'appuie pour la plupart du temps sur les <em>endpoints</em> fournis en standard, et pour quelques cas bien particuliers sur des <em>endpoints</em> développés spécifiquement, avec pour but de simplifier l'application, et d'accélérer le développement. En effet, j'ai constaté qu'il était souvent beaucoup plus rapide d'écrire un nouvel endpoint, qui accepte et renvoie des données formatées correctement, que de demander aux développeurs Java d'appeler N <em>endpoints</em> différents. D'autre part, certaines fonctions ne sont pas disponibles autrement que via les API, par exemple la récupération des questions de sécurité.</p> <h3>Scripts d'administration / débogage</h3> <p>Forgerock propose un ensemble de scripts shell utilisables pour "envelopper" les appels <strong>curl</strong>. De mon côté, j'avais développé un ensemble de scripts - avant de tomber sur ceux de Forgerock - qui permette notamment de tester rapidement la solution, sans devoir utiliser la console.<br />Dans le cadre du développement de l'application spécifique, ceci permettait rapidement de voir les effets de l'appel des différentes URL.<br />La plupart des scripts sont utilisés en mode GET. Par exemple, pour récupérer les objets <strong>user</strong> et <strong>sfa</strong> liés par leur attribut <em>UniqueIdentifier</em>, nous avions le script suivant :</p> <pre>$ cat getByUniqueId #!/bin/bash # source env.sh if [ -z $1 ] ; then echo -n "UniqueID: " read USERID else USERID=$1 fi echo "--- User ---" ./getREQ managed/user/?_queryId=get-by-field-value\&amp;field=uniqueIdentifier\&amp;value=${USERID}\&amp;_fields=uid,mail,uniqueIdentifier,userName,employeeNumber ech "--- SFA ---" ./getREQ managed/sfa/?_queryId=get-by-field-value\&amp;field=uniqueIdentifier\&amp;value=${USERID}\&amp;_fields=uid,mail,uniqueIdentifier,userName,employeeNumber </pre><p>Ce script fait appel au script plus générique <code>getREQ</code>, qui lance une requête de type GET :</p> <pre>$ cat getREQ #!/bin/bash # source env.sh if [ -z $1 ] ; then echo -n "Endpoint : " read REQ else REQ=$1 fi ENDPOINT=${IDMHOST}/openidm/${REQ} echo "Endpoint : ${ENDPOINT}" echo curl -s --insecure --header "X-OpenIDM-Username: ${IDMUSER}" --header "X-OpenIDM-Password: ${IDMPASS}" \ --header "Content-Type: application/json" --request GET ${ENDPOINT} | python -m json.tool </pre><p>Et au final, on utilise un script permettant de définir les variables d'environnement :</p> <pre>$ cat env.sh # # Environment settings # OPENIDM_SERVER=localhost OPENIDM_SERVER_PORT=8080 IDMHOST="http://${OPENIDM_SERVER}:${OPENIDM_SERVER_PORT}" IDMPASS="Passw0rd" IDMUSER="openidm-admin" </pre><p>On peut aussi par exemple utiliser un script shell pour tester l'envoi de mail via le produit :</p> <pre>$ cat sendMail # # --header "If-None-Match:*" \ # source env.sh if [ -z $1 ] ; then echo -n "TO : " read TO else TO=$1 fi ENDPOINT=${IDMHOST}/openidm/external/email/?_action=send HOST=$(hostname) curl -X --insecure --header "X-OpenIDM-Username: ${IDMUSER}" --header "X-OpenIDM-Password: ${IDMPASS}" \ --header "Content-Type: application/json" --request POST \ --data '{"from" : "idm.admin@example.com", "to" : "'$TO'", "subject": "Test","body" : "Test message from OpenIDM server '$HOST'" }' \ ${ENDPOINT} | python -m json.tool </pre><h3>Reprise de données</h3> <p>Nous avons cumulé le changement d'outil IDM avec le changement de l'annuaire LDAP, et l'introduction de nouveaux attributs sur les comptes. Ceci a parfois posé des effets de bord, voire des dommages collatéraux.</p> <p>Plusieurs programmes de reprise de données ont été réalisés, en PHP, utilisant des appels aux fonctions OpenIDM via CURL. L'avantage de travaillere directement sur OpenIDM et non pas sur l'annuaire LDAP était que les données étaient du coup synchronisées dans tous les comptes qui le nécessitaient : LDAP, AD, etc.<br />Ce mode de fonctionnement était d'autant plus nécessaire que le modèle de données OpenIDM est fait pour être souple, au détriment de la facilité d'usage : il est difficile d'utiliser des requêtes de type relationnel entre les objets et leurs attributs, sauf à passer par X jointures...</p> <p>Par exemple, lors de la phase de démarrage, il a fallu identifier tous les comptes de commerciaux (comptes SFA) non liés à un propriétaire par son attribut <em>UniqueIdentifier</em>, ou dont l'attribut était à 0.<br />Ceci a été réalisé simplement via un peu de code :</p> <pre>&lt;?php $idmHost="http://localhost:8180/openidm/"; $IDMUSER="openidm-admin"; $IDMPASS="Passw0rd" ; $curlHeaders = array ( "X-OpenIDM-Username: ".$IDMUSER , "X-OpenIDM-Password: ".$IDMPASS , "Content-Type: application/json" ); $idmurl=$idmHost.'/managed/sfa/?_queryId=query-all&amp;_fields=uid,uniqueIdentifier,mail,userName,co'; $ch=curl_init($idmurl); curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE); curl_setopt($ch,CURLOPT_HTTPHEADER,$curlHeaders); curl_setopt($ch,CURLOPT_VERBOSE,FALSE); $result=curl_exec($ch); $info = curl_getinfo($ch); curl_close($ch); $idmObjects = json_decode($result,true); $nbObj = $idmObjects["resultCount"]; echo "Nombre de Sfa a traiter: ",$nbObj,PHP_EOL; $nbIdNull=0; for ( $i = 0 ; $i &lt; $nbObj ; $i++ ) { $uniqueId=$idmObjects['result'][$i]['uniqueIdentifier']; if ( !isset($uniqueId) || $uniqueId == "00000000" || $uniqueId == null ) { $nbIdNull++; $pays = $idmObjects['result'][$i]['co'] ; if ( isset ($idmObjects['result'][$i]['mail'] ) ) { echo $pays ,';',$idmObjects['result'][$i]['userName'],';',$idmObjects['result'][$i]['mail'],PHP_EOL; } else { echo $pays,';',$idmObjects['result'][$i]['userName'],';No mail ',PHP_EOL; } } } echo "Nombre de SFA non liés : ",$nbIdNull,PHP_EOL; </pre><p>La liste était ensuite envoyée dans chaque pays, où le correspondant informatique pouvait alors assigner un compte individuel aux comptes commerciaux.</p> <h2>Endpoints spécifiques</h2> <p>Comme dit plus haut, certains <em>endpoints</em> spécifiques ont été développés pour faciliter le développement de l'application, ou également pour permettre aux équipes Windows d'interagir avec le produit (appel d'un <em>endpoint</em> OpenIDM à partir d'un script PowerShell).</p> <p>Parmi les <em>endpoints</em> spécifiques, on peut notamment en citer quelques uns, qui couvrent des besoins propres au client :</p> <ul> <li>Récupération des questions et réponses de sécurité (c'est le help-desk qui pose la question au téléphone à la personne et vérifie la réponse)</li> <li>Récupération des sites, à partir des containers de l'Active Directory</li> </ul> <p> </p> <h3>Questions de sécurité</h3> <p>Le mode de fonctionnement pour le "reset" de mot de passe est un peu spécial, car il n'est pas utilisé en mode Self-Service directement. En cas d'oubli, l'utilisateur appelle le support IT du pays, qui va aller sur la fiche utilisateur, et lui poser la question de sécurité.<br />L'utilisateur doit alors répondre à la question (par téléphone) et l'administrateur va comparer la réponse à celle affichée, puis procédera ensuite au changement de mot de passe.</p> <p>Par défaut, les informations de sécurité ne sont pas récupérées, et elles sont chiffrées. Afin de pouvoir y accéder via l'application, j'ai donc développé un <em>endpoint</em> :</p> <pre>/* * Endpoint to retreive Security Answer of a user * * Parametre : uid (uid utilisateur) * * Requete * GET * read (GET) : true / false */ /* Take the values passed in and map them to ldap attributes */ function getAns(u) { if ( u === "" ) { return { "resultCount" : "0", "result" : false } ; } var result = false; var params = { '_queryId' : 'for-userName', 'uid' : u }; var retour = openidm.query('managed/user',params, ["uid","securityAnswer","securityQuestion","sn", "_id","password"] ); result = { "resultCount" : "1", "result" : false } ; if ( retour != null ) { // On a trouve un utilisateur if ( retour.result != null &amp;&amp; retour.result.length &gt; 0 ) { logger.info("[getSecAns] Result length : {}", retour.result.length); } else { result = { "resultCount" : "0", "result" : false } ; } } var laReponse = retour.result[0].securityAnswer ; var laQuestion = retour.result[0].securityQuestion ; if ( laReponse != null ) { // Utilisation de la fonction openidm.decrypt pour récupérer la valeur en clair var answer = openidm.decrypt(laReponse); } else { var answer = "N/A"; } return { "question" : laQuestion, "answer" : answer } ; } (function(){ if (request.method === "read") { var u = request.additionalParameters.uid; var action = request.additionalParameters.action; return getAns(u); } else { throw { code : 500, message : "Unknown request type " + request.method }; } })(); </pre><p>Le script de configuration <code>conf/customSecAns.js</code> contient la déclaration de ce service :</p> <pre>{ "context" : "endpoint/getSecAns", "file" : "script/endpoints/getSecAns.js", "type" : "text/javascript" } </pre><p>L'appel au service se fait via l'URL :</p> <pre>Endpoint : http://localhost:8080/openidm/endpoint/getSecAns?uid=lsalame { "question": "Couleur-preferee", "answer": "Rouge" } </pre><p> </p> <h2>Conclusion</h2> <p>La grande force de OpenIDM est son ouverture, notamment l'utilisation de REST qui permet d'accéder aux fonctions de la solution, et la possibilité de développer soi-même ses propres <em>endpoints</em>, afin d'utiliser les API du produit.</p> <p>Les connecteurs scriptés se situent également dans la même optique d'ouverture, en permettant de réaliser assez facilement des actions très spécifiques, au prix, c'est vrai, d'un développement plus lourd que pour des connecteurs pré-paramétrés.</p> <p>Une des faiblesses de OpenIDM, tout au moins dans la version 3.1, se situe au niveau de la gestion des rôles. Il est moins intuitif de déclencher des provisionnements basés sur les rôles. Il est également plus complexe de définir des rôles basés sur des attributs. Encore une fois, il faut en passer par un script qui pourra utiliser les attributs de l'objet utilisateur.</p> <p>En règle générale, OpenIDM semble plus adapté pour des projets dans lesquels les règles métiers ne sont pas très complexes à implémenter, avec un nombre de rôles limités. Dans le cas contraire, il faudra passer par du développement, avec l'inconvénient de perdre la visibilité des liens entre personnes et rôles.</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">mar 26/04/2016 - 16:14</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/taxonomy/term/3" hreflang="fr">openidm</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Tue, 26 Apr 2016 14:14:06 +0000 Vincent 157 at https://www.vincentliefooghe.net Prise en main de OpenIDM 4 https://www.vincentliefooghe.net/index.php/content/prise-main-openidm-4 <span class="field field--name-title field--type-string field--label-hidden">Prise en main de OpenIDM 4</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>La version 4 de OpenIDM est disponible depuis fin janvier 2016 (cf. les<a href="https://backstage.forgerock.com/#!/docs/openidm/4/release-notes"> Release Notes</a>).</p> <p>Cette nouvelle version apporte son lot de changements, qui améliorent encore un peu le produit. On peut notamment citer des nouveautés du côté de l'interface d'administration :</p> <ul> <li>une nouvelle page d'accueil / dashBoard plus complète</li> <li>la possibilité de paramétrer les méthodes d'authentification, l'audit, l'e-mail, le self-service</li> <li>la définition des objets, et leur paramétrage dans l'interface (on peut désormais "construire" l'interface d'administration facilement.</li> </ul> <p>Du côté du "moteur", cette version apporte :</p> <ul> <li>la gestion du multi-comptes, via des "link qualifier"</li> <li>la gestion des relations entre objets (par exemple une relation manager / subordonné)</li> </ul> <p>Autre nouveauté (a priori) : il faut définir un schéma pour les objets managés. Jusqu'à la version 3.1, on pouvait définir dans le fichier managed.json un objet, et lui ajouter n'importe quel attribut. Ceci ne semble plus être le cas en version 4. Du coup le schéma est plus strict, et dans le mapping on a également la liste des attributs des objets (et plus uniquement les attributs des ressources).</p> <p>Voyons les quelques nouveautés</p> <h2>Dashboard</h2> <p>La page d'accueil / dashboard présente plusieurs sections :</p> <ul> <li>Quick start : on y retrouve des raccourcis vers des actions courantes (gestions des rôles, des utilisateurs, paramétrage)</li> <li>Etat de la dernière réconciliation</li> <li>Etat du système</li> <li>Liste des ressources, objets managés et mappings</li> </ul> <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/openidmDashboard.png" title="openidmDashboard.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;openidmDashboard.png&quot;}"><img src="/sites/default/files/styles/large/public/openidmDashboard.png?itok=93EVPj5p" width="363" height="480" alt="openidmDashboard.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>Dans le bandeau de menu, on a 3 options principales : Dashboard, Configure (configuration de la plate-forme), Manage (gestion des objets).</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/S%C3%A9lection_008.png" title="Sélection_008.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sélection_008.png&quot;}"><img src="/sites/default/files/styles/large/public/S%C3%A9lection_008.png?itok=6US3W7_L" width="480" height="243" alt="Sélection_008.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>Le menu de configuration n'est disponible que pour les utilisateurs avec le rôle <em>openidm-admin</em>.</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/S%C3%A9lection_009.png" title="Sélection_009.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sélection_009.png&quot;}"><img src="/sites/default/files/styles/large/public/S%C3%A9lection_009.png?itok=2e_vdEr-" width="480" height="234" alt="Sélection_009.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p> </p> <h2>Configuration</h2> <p>Dans cette partie, on trouve désormais des paramétrages qui n'étaient faisables que via les fichiers json dans la version 3.1, par exemple le paramétrage des modes d'authentification (PassThrough, internal, managed) :</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/S%C3%A9lection_010.png" title="Sélection_010.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sélection_010.png&quot;}"><img src="/sites/default/files/styles/large/public/S%C3%A9lection_010.png?itok=IGht7PbU" width="480" height="324" alt="Sélection_010.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>Ou encore le paramétrage de la messagerie</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/S%C3%A9lection_012.png" title="Sélection_012.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sélection_012.png&quot;}"><img src="/sites/default/files/styles/large/public/S%C3%A9lection_012.png?itok=40L_TKTN" width="480" height="220" alt="Sélection_012.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <h2>Configuration des mappings</h2> <p>La configuration des mappings a un peu évolué. On retrouve la grille de correspondance, mais les transformations et les valeurs par défaut sont affichées différemment : entre parenthèses pour les valeurs par défaut, et avec une icône pour signaler les transformations</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/S%C3%A9lection_016.png" title="Sélection_016.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sélection_016.png&quot;}"><img src="/sites/default/files/styles/large/public/S%C3%A9lection_016.png?itok=Jr9lLzax" width="480" height="198" alt="Sélection_016.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <h2>Définition du schéma des objets managés</h2> <p>A la différence de la version 3, les objets managés ont maintenant un écran de paramétrage du schéma, qui sert également à gérer l'affichage sur l'écran</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/S%C3%A9lection_019.png" title="Sélection_019.png" data-colorbox-gallery="gallery-all-883d8oly0Bs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Sélection_019.png&quot;}"><img src="/sites/default/files/styles/large/public/S%C3%A9lection_019.png?itok=_PlF398j" width="480" height="296" alt="Sélection_019.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>L'attribut "Viewable" par exemple permet d'afficher l'attribut dans l'écran de détail. L'attribut "Searchable" permet d'ajouter le champ dans l'écran de recherche (la grille). On peut aussi positionner l'attribut avec les flêches pour le monter ou le descendre dans l'écran.</p> <h2>Conclusion rapide</h2> <p>Après quelques minutes, on retrouve vite ses marques si on est habitué à OpenIDM 3.1, mais on découvre aussi des nouveautés bien intéressantes.</p> <p>Reste à tester plus en détail les relations entre objets, ou encore la gestion des comptes multiples ainsi que la gestion des rôles de provisionnement, qui semble améliorée et simplifiée.</p> <p> </p> <p> </p> <p> </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">mar 15/03/2016 - 16:13</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/taxonomy/term/3" hreflang="fr">openidm</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> <article data-comment-user-id="0" id="comment-35" class="comment js-comment by-anonymous"> <mark class="hidden" data-comment-timestamp="1465427223"></mark> <footer class="comment__meta"> <p class="comment__submitted">Soumis par <span lang="" typeof="schema:Person" property="schema:name" datatype="">Pierre</span> le jeu 09/06/2016 - 01:07</p> <a href="/index.php/comment/35#comment-35" hreflang="und">Permalien</a> </footer> <div class="content"> <h3><a href="/index.php/comment/35#comment-35" class="permalink" rel="bookmark" hreflang="und">Synchroniser les password policies de OpenDJ avec OpenIDM</a></h3> <div class="clearfix text-formatted field field--name-comment-body field--type-text-long field--label-hidden field__item">Bonjour,Je cherche un moyen d'appliquer une password policy définie sur OpenDJ à un password que l'on (par exemple) voudrait mettre à jour via la webui du self-service <em>PasswordReset</em> fournie par OpenIDM, sais-tu comment faire ca ?En d'autres termes :Nous avons un LDAP (OpenDJ) et un openIDM qui sont exploités de la manière suivante :- LDAP (OpenDJ) : Pour l'authentification d'une appli maison (qui s'appuie sur un le LDAP de OpenDJ). Cet OpenDJ possède ses propres password policies (subentry based). Ce sont celles-ci (Password policies) que nous voudrions appliquer via OpenIDM.Lorsque qu'un user est créé via cette appli maison (elle ne permet que la création, pas d'update d'attributs) le password est confronté à la password policy de cet OpenDJ....- Self-service (passordReset) OpenIDM : Qui permet aux utilisateurs de l'appli maison de gérer eux-meme leur password (la mise à jour de leur password principalement). L'appli maison ne permet pas cette mise à jour via son interface, nous contournons donc ce problème avec le self-service de OpenIDM. Par exemple :-&gt; Un user qui voudrait mettre à jour son password en passant par la webui <em>passwordReset</em> devrait etre contraint de respecter la password policy déclarée sur OpenDJ.... J'ai essayé d'etre clair, tous cela reste assez nouveau pour moi, n'hésite pas à me demander des précisions si besoin. Merci !</div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=35&amp;1=default&amp;2=und&amp;3=" token="hrTy2p72mX2XwQuDt7ER7zut-1ZjC3l0Hx116hIwPPg"></drupal-render-placeholder> </div> </article> </section> Tue, 15 Mar 2016 15:13:25 +0000 Vincent 155 at https://www.vincentliefooghe.net OpenIDM - comment remplacer la suppression par une mise à jour https://www.vincentliefooghe.net/index.php/content/openidm-comment-remplacer-la-suppression-par-une-mise-%C3%A0-jour <span class="field field--name-title field--type-string field--label-hidden">OpenIDM - comment remplacer la suppression par une mise à jour</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>J'ai eu récemment le cas d'un client qui voulait, lors de la suppression d'un objet <em>user</em>, mettre à jour l'annuaire LDAP sur lequel l'utilisateur avait un compte, plutôt que supprimer ce compte.</p> <p>Pour cela, il faut tout d'abord modifier l'action liée à la situation <strong>SOURCE_MISSING</strong>, pour utiliser Unlink plutôt que Delete (<em>en fait, si on garde l'opération Delete, on peut lancer un script, mais l'objet cible sera quand même supprimé par la suite</em>).</p> <p>On assigne donc l'action <strong>UNLINK</strong> à la situation <strong>SOURCE_MISSING</strong> dans le paramétrage.</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/ModificationSOURCE_MISSING.png" title="ModificationSOURCE_MISSING.png" data-colorbox-gallery="gallery-all-kKyhRYx5HCI" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;ModificationSOURCE_MISSING.png&quot;}"><img src="/sites/default/files/styles/large/public/ModificationSOURCE_MISSING.png?itok=SmJx8HlR" width="480" height="180" alt="ModificationSOURCE_MISSING.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>Puis on va ajouter un script sur l'événement unlink :</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_067.png" title="Forgerock_067.png" data-colorbox-gallery="gallery-all-kKyhRYx5HCI" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_067.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_067.png?itok=B-nv7K2q" width="480" height="229" alt="Forgerock_067.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>Pour plus de souplesse, on utilise un script externe. J'ai tendance à structurer mes scripts par connecteur, d'où le sous-répertoire LDAP :</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_068.png" title="Forgerock_068.png" data-colorbox-gallery="gallery-all-kKyhRYx5HCI" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Forgerock_068.png&quot;}"><img src="/sites/default/files/styles/large/public/Forgerock_068.png?itok=EftJ-uWC" width="480" height="431" alt="Forgerock_068.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /> </a> </div> </div> </article> </p> <p>Le contenu du script onUnlink.js est le suivant :</p> <pre>/** * Ce script est utilisé pour gérer le UnLink * A cet instant, seul target._id est disponible. Il faut donc utiliser openidm.read * pour récupérer tout l'objet. * */ logger.info("[LDAP/onUnlink] target _id : {} " , target._id); var ldapUser = openidm.read('system/ldap/account/' + target._id ); logger.info("[LDAP/onUnlink] ldapUser _id : {} - uid {}" , ldapUser._id, ldapUser.uid); var dateUnlink = (new Date()).toString(); ldapUser.description="DELETED-"+dateUnlink; ldapUser.AccountStatus="DELETED"; openidm.update('system/ldap/account/' + target._id, null, ldapUser); </pre><p>Lorsqu'on supprimer l'objet User, on constate que son compte est toujours présent dans le LDAP, avec la description et le status mis à jour :</p> <pre>{ "pagedResultsCookie": null, "remainingPagedResults": -1, "result": [ { "AccountStatus": "DELETED", "_id": "d4f7b091-bad1-4c97-8bec-9e358038d686", "cn": "Virginia WOLF", "description": "DELETED-Thu Jan 28 2016 15:53:27 GMT+0100 (CET)", "dn": "uid=vwolf,ou=People,dc=example,dc=com", "givenName": "Virginia", "sn": "WOLF, "uid": "juwolanin" } ], "resultCount": 1 }</pre><p>Dans le processus du client, un batch va aller récupérer tous les soirs les entrées avec le statut "DELETED", pour les sauvegarder, afin de pouvoir éventuellement les restaurer si besoin.</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">jeu 28/01/2016 - 16:15</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/taxonomy/term/3" hreflang="fr">openidm</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Thu, 28 Jan 2016 15:15:20 +0000 vincentl 148 at https://www.vincentliefooghe.net