Paramètre synchronisation annuaire LDAP Documentum

De EjnTricks
Révision de 14 janvier 2016 à 18:03 par Etienne (discussion | contributions)

(diff) ← Version précédente | Voir la version courante (diff) | Version suivante → (diff)

Sur le serveur Documentum, un job est fourni en standard pour la synchronisation des utilisateurs et des groupes. Ce job recherche l'ensemble des configurations LDAP, objet dm_ldap_config, depuis la docbase et réalise la mise à jour des utilisateurs. Les administrateurs utilisent en général l'application DA pour mettre en place de telle configuration. Cependant, cela est particulièrement simple et cet article présente les différentes options.

Hand-icon.png Votre avis

Current user rating: 98/100 (1 votes)

 You need to enable JavaScript to vote


Objet dm_ldap_config

Cet objet est utilisé lors de:

  • La connexion des utilisateurs, afin d'identifier l'annuaire sur lequel l'authentification est effectuée.
  • La synchronisation des comptes.

Ce paragraphe ne traitera que des paramètres liés à la synchronisation.

Attribut Valeur
person_obj_class Classe "LDAP" des utilisateurs.
group_obj_class Classe "LDAP" des groupes.
per_search_base Recherche de base pour les utilisateurs sur l'annuaire.
grp_search_base Recherche de base pour les groupes sur l'annuaire.
per_search_filter Filtre des utilisateurs à synchroniser.
grp_search_filter Filtre des groupes à synchroniser.
user_subtype Type Documentum des utilisateurs à créer.
rename_user_option Si true, les comptes sont renommés lors de la modification du nom des utilisateurs.
deactivate_user_option Si true, désactivation d'un utilisateur si il n'est plus trouvé dans l'annuaire.

Il est préférable d'utiliser cette option et de ne pas supprimer le compte.

rename_group_option Si true, les groupes sont renommés lors de la modification du nom des utilisateurs.
import_mode Mode de synchronisation, permet de spécifier utilisateurs ET/OU groupes.

Comme pour toutes synchronisation LDAP, il est nécessaire de mapper les données depuis l'annuaire vers les objets créés dans la docbase. Cette configuration s'effectue à travers les cinq attributs suivants, liés les uns aux autres en fonction des valeurs aux mêmes positions.

Attribut Valeur
map_attr Nom de l'attribut sur l'objet dans la docbase.
map_val Attribut depuis l'annuaire LDAP.
map_attr_type Type auquel s'applique le mapping, dm_user ou dm_group.
map_val_type Le type de valeur, permettant de fixer une valeur, récupérer celle de l'annuaire ou d'effectuer de légère modification.
map_rejection Paramètre de rejet en cas d'erreur de mapping.

Certains attributs acceptent des valeurs particulières

Attribut Valeurs Possibles Description
map_val_type A Récupération de la valeur depuis l'annuaire LDAP.
E Utilisation d'une expression pour calculer la valeur.
V Valeur en "dur".
map_rejection 0 Le traitement est poursuivi en cas d'erreur.
1 Le traitement est arrêté si l'attribut n'existe pas, ou est vide, dans l'annuaire LDAP.
2 Le traitement est arrêté pour toutes erreurs. En cas de configuration d'un attribut obligatoire dans la docbase, cette valeur est utilisée quelque soit le paramétrage.

Mode d'import

Valeurs possibles

Comme indiqué dans la liste des paramètres, il est possible de choisir le mode de synchronisation afin de récupérer les utilisateurs ET/OU les groupes. Dans la documentation Object Reference, il existe une ambiguïté sur les valeurs à utiliser, au nombre de trois:

  • user
  • group
  • both

Or dans la description, il est indiqué:

Valid values are:

• user

• group

• all

The default value is all.


Cependant la valeur all n'est pas valide, c'est bien la valeur both qu'il faut utiliser.

Lecture configuration depuis dm_ldap_config

Cette configuration est configurée en analysant le code de synchronisation disponible dans le jar dmldap.jar, dans le répertoire shared/jboss4.3.0/server/DctmServer_MethodServer/deploy/ServerApps.ear/APP-INF/lib/dmldap.jar sous l'installation du content server.

Dans cette libraire, la fonction principale est processJob. Celle-ci va préparer l'exécution, à partir des arguments du job et de la configuration LDAP.

    private void processJob()
        throws DmLdapException
    {
        Tracer.logDebug("Building List of Ldap Configs to be synchronized...");
        buildLdapConfigsListForSynchronization();
        m_synchronizationContextBuilder = new SynchronizationContextBuilder(m_repoHelper);
        for(Iterator i$ = m_ldapSynchronizationList.iterator(); i$.hasNext(); Tracer.logMsg(""))
        {
            IDfId ldapConfigId = (IDfId)i$.next();
            String ldapConfigName = getEnabledLdapConfigObjectName(ldapConfigId);
            Tracer.logMsg("");
            Tracer.logMsg("================================================================================");
            try
            {
                DataExchanger.clearStatus();
                IDfSysObject ldapConfigObject = m_repoHelper.getLdapConfigObject(ldapConfigId);
                Tracer.logMsg((new StringBuilder()).append("Starting Sychronization for ldap config object >>>").append(ldapConfigName).append("<<< ...").toString());
                prepareSync(ldapConfigObject);
                processSync();
                saveLdapConfigObject(ldapConfigName);
            }
            catch(DmLdapException dlEx)
            {
                Tracer.logMsg(Utilities.getMessage("LDAP_UNEX_ERROR", dlEx.getMessage()));
                Tracer.logError(dlEx);
                Tracer.logWarn((new StringBuilder()).append("  **** Skipping Ldap Config Object - ").append(ldapConfigName).append(" ****").toString());
                DataExchanger.setJobStatus(JobStatus.FAILED);
            }
            catch(DfException dfEx)
            {
                Tracer.logMsg(Utilities.getMessage("LDAP_UNEX_ERROR", dfEx.getMessage()));
                Tracer.logError(dfEx);
                Tracer.logWarn((new StringBuilder()).append("  **** Skipping Ldap Config Object - ").append(ldapConfigName).append(" ****").toString());
                DataExchanger.setJobStatus(JobStatus.FAILED);
            }
            Tracer.logMsg((new StringBuilder()).append("Synchronization of ldap config object >>>").append(ldapConfigName).append("<<< is finished").toString());
            Tracer.logMsg("================================================================================");
        }

    }

La lecture des arguments s'effectue donc à partir de la fonction prepareSync, dont l'argument est la représentation java de l'objet dm_ldap_config.

    private void prepareSync(IDfSysObject ldapConfigObject)
        throws DmLdapException
    {
        m_synchronizationContext = new SynchronizationContext();
        m_synchronizationContextBuilder.buildSynchronizationContext(ldapConfigObject, m_jobArgs, m_synchronizationContext);
        m_userSynchronization = null;
        m_groupSynchronization = null;
        DirectoryProcessorFactory dirProcessorFactory = DirectoryProcessorFactory.getDirectoryProcessorFactory();
        m_dirProcessor = dirProcessorFactory.createDirectoryProcessor(m_synchronizationContext, m_repoHelper);
        m_dirProcessor.initialize();
        SynchronizerFactory syncFactory = SynchronizerFactory.getSynchronizeFactory();
        if(m_synchronizationContext.getImportMode() == ImportMode.USERS)
        {
            Tracer.logDebug("Initializing User Synchronization...");
            m_userSynchronization = syncFactory.createUserSynchronizer(m_synchronizationContext, m_repoHelper, m_dirProcessor);
            Tracer.logDebug("User Synchronization initialized");
            Tracer.logDebug("");
            m_userSynchronization.dumpRootDSE();
            DataExchanger.setLastRunTime(m_userSynchronization.getLdapTimeStamp());
        } else
        if(m_synchronizationContext.getImportMode() == ImportMode.GROUPS)
        {
            Tracer.logDebug("Initializing Group Synchronization...");
            m_groupSynchronization = syncFactory.createGroupSynchronizer(m_synchronizationContext, m_repoHelper, m_dirProcessor);
            Tracer.logDebug("Group Synchronization initialized");
            Tracer.logDebug("");
            m_groupSynchronization.dumpRootDSE();
            DataExchanger.setLastRunTime(m_groupSynchronization.getLdapTimeStamp());
        } else
        {
            Tracer.logDebug("Initializing User Synchronization...");
            m_userSynchronization = syncFactory.createUserSynchronizer(m_synchronizationContext, m_repoHelper, m_dirProcessor);
            Tracer.logDebug("User Synchronization initialized");
            Tracer.logDebug("");
            Tracer.logDebug("Initializing Group Synchronization...");
            m_groupSynchronization = syncFactory.createGroupSynchronizer(m_synchronizationContext, m_repoHelper, m_dirProcessor);
            m_groupSynchronization.setMemberUserSynchronizer(m_userSynchronization);
            Tracer.logDebug("Group Synchronization initialized");
            Tracer.logDebug("");
            m_userSynchronization.dumpRootDSE();
            DataExchanger.setLastRunTime(m_userSynchronization.getLdapTimeStamp());
        }
    }

En fonction de la valeur retournée par m_synchronizationContext.getImportMode(), les utilisateurs ET/OU groupes sont synchronisés. La variable m_synchronizationContext est construite par la méthode buildSynchronizationContext de l'instance de SynchronizationContextBuilder, variable m_synchronizationContextBuilder.

    public void buildSynchronizationContext(IDfSysObject ldapConfigObject, JobArgs jobArgs, SynchronizationContext synchronizationContext)
        throws DmLdapException
    {
        Tracer.logDebug("Building SynchronizationContext Object ...");
        m_ldapConfigObject = ldapConfigObject;
        m_jobArgs = jobArgs;
        m_synchronizationContext = synchronizationContext;
        setLdapConfigName();
        setLdapConfigId();
        setDirectoryType();
        setLdapHost();
        setLdapPort();
        setSSLMode();
        if(m_synchronizationContext.isSslEnabled())
        {
            setSSLPort();
            setCertDbLocation();
        }
        setBindDN();
        setBindPswd();
        setImportMode();
        setRenameUserOption();
        setDeactivateUserOption();
        setRenameGroupOption();
        setDomainRequiredMode();
        setSyncronizationMode();
        setUserSubType();
        setUserObjectClass();
        setGroupObjectClass();
        setUserSearchBase();
        setGroupSearchBase();
        setUserSearchFilter();
        setGroupSearchFilter();
        setAttrMaps();
        setLastRunTime();
        setLastChangeNo();
        setJobArgs();
        Tracer.logDebug(m_synchronizationContext.toString());
    }

Dans le cadre de cette article, la fonction setImportMode doit être étudiée.

    private void setImportMode()
        throws DmLdapException
    {
        if(m_jobArgs.isImportModeGiven().booleanValue())
            m_synchronizationContext.setImportMode(m_jobArgs.getImportMode());
        else
            try
            {
                String importMode = m_ldapConfigObject.getString("import_mode");
                if(!Utilities.checkString(importMode))
                {
                    Tracer.logInfo(Utilities.getMessage("DMLS_SET_DEFAULT_VALUE", "import_mode", DEFAULT_VALUE_IMPORT_MODE.getValue()));
                    m_synchronizationContext.setImportMode(DEFAULT_VALUE_IMPORT_MODE);
                } else
                {
                    m_synchronizationContext.setImportMode(ImportMode.getImportMode(importMode));
                }
            }
            catch(DfException dfEx)
            {
                throw new DmLdapException(dfEx);
            }
            catch(IllegalArgumentException iaEx)
            {
                throw new DmLdapException(iaEx);
            }
    }

Dans ce cas, la valeur est récupérée depuis l'objet dm_ldap_config et est convertie à partir de la fonction getImportMode de la classe com.documentum.ldap.internal.sync.ImportMode.

package com.documentum.ldap.internal.sync;


public final class ImportMode extends Enum
{

    public static final ImportMode[] values()
    {
        return (ImportMode[])$VALUES.clone();
    }

    public static ImportMode valueOf(String name)
    {
        return (ImportMode)Enum.valueOf(com/documentum/ldap/internal/sync/ImportMode, name);
    }

    private ImportMode(String s, int i, String value)
    {
        super(s, i);
        m_value = value;
    }

    public String getValue()
    {
        return m_value;
    }

    public static ImportMode getImportMode(String value)
        throws IllegalArgumentException
    {
        ImportMode importModes[] = values();
        ImportMode arr$[] = importModes;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            ImportMode importMode = arr$[i$];
            if(value.equalsIgnoreCase(importMode.getValue()))
                return importMode;
        }

        throw new IllegalArgumentException((new StringBuilder()).append("Cannot be parsed into ImportMode enum : '").append(value).append("'").toString());
    }

    public static final ImportMode USERS;
    public static final ImportMode GROUPS;
    public static final ImportMode BOTH;
    private String m_value;
    private static final ImportMode $VALUES[];

    static 
    {
        USERS = new ImportMode("USERS", 0, "users");
        GROUPS = new ImportMode("GROUPS", 1, "groups");
        BOTH = new ImportMode("BOTH", 2, "both");
        $VALUES = (new ImportMode[] {
            USERS, GROUPS, BOTH
        });
    }
}

Une boucle est donc réalisée sur un clone du tableau $VALUES afin de trouver l'instance de ImportMode, dont les déclarations définissent uniquement les valeurs:

  • users
  • groups
  • both


Lecture configuration depuis dm_job

Il est également possible de spécifier la valeur dans les arguments du job. Lors de l'exécution de la fonction setImportMode, l'instruction if(m_jobArgs.isImportModeGiven().booleanValue()) a été considérée comme retournant false, afin de valider la configuration sur l'objet dm_ldap_config. La suite de cette étude va permettre de contrôler que les arguments possibles sur l'objet dm_job ne contiennent pas la valeur all.

La lecture des arguments s'effectue durant l'exécution de la fonction prepareJob.

    private void prepareJob(Map jobArguments, PrintWriter printWriter)
        throws DmLdapException
    {
        Tracer.logMsg("Preparing LDAP Synchronization...");
        DfMethodArgumentManager methodArgsManager;
        try
        {
            methodArgsManager = new DfMethodArgumentManager(jobArguments);
        }
        catch(DfException dfEx)
        {
            throw new DmLdapException(dfEx);
        }
        m_jobArgs = new JobArgs();
        JobArgsProcessor jobArgsProcessor = new JobArgsProcessor(m_jobArgs);
        jobArgsProcessor.parseJobArgs(methodArgsManager);
        connectToRepository();
        checkJobId();
        if(s_syncLaunchMode == 0)
            Tracer.createReportWriter(m_jobArgs.getRepositoryName(), m_jobArgs.getRepositoryOwnerName(), m_jobArgs.getMethodTraceLevel(), m_jobArgs.getJobId(), printWriter);
    }

l'instance de JobArgsProcessor va alors permettre de lire l'ensemble des arguments positionnés sur l'objet dm_job en cours d'exécution, par la méthode parseJobArgs.

    public void parseJobArgs(DfMethodArgumentManager methodArgsManager)
        throws DmLdapException
    {
        m_methodArgsManager = methodArgsManager;
        processMethodTraceLevel();
        DumpJobArguments();
        Tracer.logDebug("Processing Job Arguments ...");
        processRepositoryName();
        processRepositoryOwnerName();
        processRepositoryOwnerDomain();
        processRepositoryOwnerPassword();
        processRenameUserOption();
        processRenameGroupOption();
        processDeactivateUserOption();
        processImportMode();
        processSynchronizationMode();
        processGroupSaveMemberLimit();
        processImportFilter();
        processJobId();
        processPageSize();
        processSourceLdapConfig();
        processCreateDefaultCabinetOption();
        processAlphaCaseUserLoginName();
        Tracer.logDebug("Processed Job Arguments");
        Tracer.logDebug(m_jobArgs.toString());
    }

Comme son nom l'indique, la méthode intéressante pour cet article est processImportMode.

    private void processImportMode()
        throws DmLdapException
    {
        if(!m_methodArgsManager.isArgumentProvided("import_mode"))
        {
            Tracer.logDebug(Utilities.getMessage("DMLS_SET_DEFAULT_VALUE", "import_mode", DEFAULT_VALUE_IMPORT_MODE.getValue()));
            m_jobArgs.setImportMode(DEFAULT_VALUE_IMPORT_MODE);
            return;
        } else
        {
            m_jobArgs.setImportMode(extractImportMode());
            m_jobArgs.setImportModeGiven(true);
            return;
        }
    }

La constante DEFAULT_VALUE_IMPORT_MODE est utilisée, représentant la valeur both, dans le cas où le paramètre import_mode n'est pas disponible. Celle-ci est construite au chargement de la classe.

    static 
    {
        DEFAULT_VALUE_IMPORT_MODE = ImportMode.BOTH;
        DEFAULT_VALUE_FULL_SYNCHRONIZATION = SynchronizationMode.INCREMENTAL;
        DEFAULT_VALUE_ALPHA_CASE_USER_LOGIN_NAME = AlphaCase.AS_IS;
    }

Si le paramètre est fourni, celui-ci est traité dans la fonction extractImportMode.

    private ImportMode extractImportMode()
        throws DmLdapException
    {
        String importMode = extractArgStringValue("import_mode");
        try
        {
            return ImportMode.getImportMode(importMode);
        }
        catch(IllegalArgumentException iaexcep)
        {
            throw new DmLdapException(iaexcep);
        }
    }

Finalement, le traitement est le même que la lecture de la configuration à partir de l'objet dm_ldap_config, confirmant une nouvelle fois les valeurs disponibles.


Exemple de mapping

Malgré la bonne rédaction de la documentation sur les mappings des propriétés, rien n'est plus parlant qu'un exemple. L'objectif de cette exemple est d'effectuer le mapping suivant.

Attribut Valeur Objectif
map_attr user_name Copie (map_val_type = A) de cn, depuis LDAP, dans user_name des objets dm_user.

Le traitement doit se terminer en cas d'erreur.

map_val cn
map_attr_type dm_user
map_val_type A
map_rejection 2
map_attr user_os_name Copie (map_val_type = A) de uid, depuis LDAP, dans user_name des objets dm_user.

Le traitement doit se terminer en cas d'erreur.

map_val uid
map_attr_type dm_user
map_val_type A
map_rejection 2
map_attr user_login_name Copie (map_val_type = A) de uid, depuis LDAP, dans user_login_name des objets dm_user.

Le traitement doit se terminer en cas d'erreur.

map_val uid
map_attr_type dm_user
map_val_type A
map_rejection 2
map_attr user_address Copie (map_val_type = A) de mail, depuis LDAP, dans user_address des objets dm_user.

Le traitement doit se terminer en cas d'erreur.

map_val mail
map_attr_type dm_user
map_val_type A
map_rejection 2
map_attr group_name Copie (map_val_type = A) de cn, depuis LDAP, dans group_name des objets dm_group.

Le traitement doit se terminer en cas d'erreur.

map_val cn
map_attr_type dm_group
map_val_type A
map_rejection 2
map_attr description Calcul (map_val_type = E) de la description des objets dm_user depuis description de LDAP.

Le traitement ne doit pas se terminer en cas d'erreur.

map_val ${description#255}
map_attr_type dm_user
map_val_type E
map_rejection 0
map_attr client_capability Valeur 2 (map_val_type = V) pour client_capability des objets dm_user.

Le traitement doit se terminer en cas d'erreur.

map_val 2
map_attr_type dm_user
map_val_type V
map_rejection 2

Cette configuration permet de mettre en évidence les différents modes de mapping des données:

  • Copie.
  • Expression.
  • Valeur en "dur".

La configuration à mettre en place est donc la suivante:

 map_attr                [0]: user_name
                         [1]: user_os_name
                         [2]: user_login_name
                         [3]: user_address
                         [4]: group_name
                         [5]: description
                         [6]: client_capability
 map_val                 [0]: cn
                         [1]: uid
                         [2]: uid
                         [3]: mail
                         [4]: cn
                         [5]: ${description#255}
                         [6]: 2
 map_attr_type           [0]: dm_user
                         [1]: dm_user
                         [2]: dm_user
                         [3]: dm_user
                         [4]: dm_group
                         [5]: dm_user
                         [6]: dm_user
 map_val_type            [0]: A
                         [1]: A
                         [2]: A
                         [3]: A
                         [4]: A
                         [5]: E
                         [6]: V
 map_rejection           [0]: 2
                         [1]: 2
                         [2]: 2
                         [3]: 2
                         [4]: 2
                         [5]: 0
                         [6]: 2

Dans cet exemple, le mapping sur la description est une expression pour extraire les 255 premiers caractères. Or, lors de la synchronisation des warnings peuvent apparaître au niveau de la trace d'exécution, lorsque les valeurs dans LDAP ne contiennent pas 255 caractères. C'est pourquoi le paramètre map_rejection est positionné à 0, afin de poursuivre malgré tout le traitement.