Sonar Configuration LDAP

De EjnTricks

Hand-icon.png Votre avis

Current user rating: 85/100 (1 votes)

 You need to enable JavaScript to vote


Icon File Owner.png Référencement compte administrateur

Cet article présente la configuration d'un annuaire LDAP dans Sonar. Attention, lors de l'action de l'annuaire LDAP, TOUS les comptes seront authentifiés sur celui ci. Si celui ci n'est pas présent dans l'annuaire, il deviendra impossible de se connecter à Sonar. Un compte existant, dans cet annuaire, est donc référencé dans Sonar par précaution.


Puis il faut attribué les droits d'administration à ce compte, en cliquant sur le lien select dans la colonne des groupes. Les groupes disponibles et affectés à celui-ci sont alors présentés:


Pour ajouter les droits d'administration, il faut sélectionner le groupe sonar-administrators et l'ajouter à la liste des groupes affectés en cliquant sur le bouton select. Après enregistrement, l'utilisateur sera administrateur.

Afin de sécuriser encore plus la procédure d'installation, les droits d'administration sont attribués temporairement au compte anonyme.


Le compte administrateur, initialisé à l'installation de l'application, reste cependant actif.

Cependant avec les fonctionnalités de synchronisation des groupes sur la version 1.1, la composition des groupes est synchronisé dès la connexion de l'utilisateur. Les différentes compositions de groupe préalablement mises en place seront perdues, et i lfaut que les groupes dans Sonar soit équivalent aux groupes dans LDAP.

Pour mémoire, les groupes initiaux dans Sonar, permettant d'initialiser l'annuaire, sont:

  • sonar-administrators: Ensemble des administrateurs de Sonar.
  • sonar-users: Ensemble des utilisateurs de Sonar.

Dependencies.gif Installation plugin

Après s'être assuré de la création du compte administrateur, existant dans l'annuaire, il faut installer le plugin LDAP. Ceci s'effectue en allant dans la console d'administration, puis en cliquant sur le lien Update center. Sur la liste des plugin, il faut cliquer sur le lien LDAP permettant de visualiser un descriptif de celui et surtout le lien de téléchargement.


Une fois téléchargé, il est nécessaire de relancer le serveur, par un simple arrêt/relance de Tomcat par exemple. Une fois redémarré, il est possible de vérifier l'installation de celui-ci en retournant dans la page Update center et de constater qu'il figure bien dans la liste des plugins installés.


Icon-Configuration-Settings.png Configuration LDAP

Configuration simple

Une fois installé, la confiugration du plugin s'effectue en modifiant le fichier sonar.properties, se situant dans le répertoire WEB-INF/classes/conf de l'application, dans le cas de cette étude sous /var/lib/tomcat6/webapps/sonar/WEB-INF/classes/conf. Les valeurs saisies, dans le cadre de cet article, sont en relation avec l'installation faite de OpenLDAP sur un serveur Ubuntu.

Les paramètres mis en place sont les suivants:

Paramètre Valeur Description
ldap.url ldap://localhost:389 Sonar étant installé sur la même machine que l'annuaire.
ldap.baseDn ou=people,dc=ejnserver,dc=fr Tous les utilisateurs sont déclarés sous cet ou.
ldap.bindDn cn=admin,dc=ejnserver,dc=fr Comptes administrateur de l'annuaire
ldap.bindPassword ADMIN_PASSWORD Le mot de passe du compte défini dans ldap.bindDn

Une fois sauvegardé, le serveur applicatif est redémarré est les authentifications sont alors vérifiées sur l'annuaire référencé. Il est donc possible de ce connecter en administrateur avec le compte créé précédemment. L'ajout dans le groupe d'administration de l'utilisateur anonyme n'est donc plus nécessaire (il n'a pas été nécessaire de l'utiliser heureusement) et il faut penser à lui supprimer ces permissions.

Dans le cadre de cette installation, les utilisateurs doivent être déclarés préalablement sous Sonar pour pouvoir s'authentifier. Un paramètre est disponible afin de créer ceux-ci dès la tentative de connexion mais elle n'a pas été exploitée.

Configuration avancée

L'exemple précédent est une configuration assez simple du plugin car seuls les paramètres de connexion ont été mis en place. Cependant, deux paramètres, dont les valeurs par défaut sont générales opérationnels, sont à prendre en compte.

Paramètre Valeur par défaut Description
ldap.loginAttribute uid Propriété dans l'annuaire LDAP correspondant au login de l'utilisateur.
ldap.userObjectClass inetOrgPerson Classe valide pour les entrées dans LDAP.

Le paramètre ldap.userObjectClass est de loin le plus important. En effet, celui-ci spécifie la classe requise des entrées dans l'annuaire LDAP pour valider l'authentification. Un compte pourrait être déclarée avec la classe simpleSecurity, par exemple, et pourtant la connexion ne pourra jamais aboutir.

Création automatique des utilisateurs

Lors de l'utilisation d'un annuaire LDAP, il n'est pas nécessaire de créer le compte au niveau de Sonar. A la première tentative de connexion des utilisateurs, le compte peut être ajouté automatiquement. Pour cela il faut activer le paramètre sonar.authenticator.createUsers en spécifiant la valeur true.


Update icon.png Mise à jour version 1.1

Malgré l'indexe mineure sur le numéro de version, la modification est assez importante et entraîne des modifications obligatoires au niveau de la configuration. Cette version introduit le mapping des groupes et la configuration des utilisateurs est modifiée.

Paramètre Ancien paramètre Valeur par défaut Description
ldap.user.baseDn ldap.baseDn ou=people,dc=ejnserver,dc=fr Base de recherche pour les utilisateurs.
ldap.user.loginAttribute ldap.loginAttribute uid Propriété dans l'annuaire LDAP correspondant au login de l'utilisateur.
ldap.user.objectClass ldap.userObjectClass inetOrgPerson Classe valide pour les entrées dans LDAP.
ldap.user.realNameAttribute   cn Propriété dans l'annuaire LDAP correspondant au nom complet de l'utilisateur.
ldap.user.emailAttribute   mail Propriété dans l'annuaire LDAP correspondant au mail de l'utilisateur.

Une configuration de mapping des groupes est également mis en place, sur le même principe que les utilisateurs.

Paramètre Valeur Description
ldap.group.baseDn ou=groups,dc=ejnserver,dc=fr Base de recherche pour les groupes.
ldap.group.objectClass groupOfUniqueNames Classe valide pour les entrées dans LDAP. La valeur par défaut est groupOfUniqueNames. Dans le cadre de cette installation, la classe des groupes est groupOfNames.
ldap.group.idAttribute cn Propriété dans l'annuaire LDAP correspondant à l'identifiant du groupe.
ldap.group.memberAttribute uniqueMember Propriété dans l'annuaire LDAP contenant les comptes composant le groupe. Dans le cadre de cette installation, cette propriété est member.

La propriété ldap.group.objectClass doit être obligatoire. Sans cette configuration, le plugin ne fonctionne pas.


Attention, il existe deux pré requis pour le bon fonctionnement du mapping des groupes.

  • Les groupes ne peuvent pas être dynamiques, ils doivent être statiques.
  • Les utilisateurs doivent avoir la propriété memberOf. Dans le cadre de l'utilisation de OpenLDAP, il est donc nécessaire d'installer l'overlay memberOf.


Enfin, la dernière modification, et pas des moindres, concerne la configuration du mode d'authentification. Le paramètre sonar.authenticator.class est remplacé par sonar.security.realm, dont la valeur doit être LDAP. Si cette modification est oubliée, la trace suivante est observée dans la log de Sonar.

Les modifications sont donc assez importante et le fichier subit de nombreuses modifications.


Update icon.png Mise à jour version 1.2

Malgré l'indexe mineure sur le numéro de version, des modifications majeures sont apportées sur la configuration concernant la validation des utilisateurs et des groupes. Les filtres class et attribute pour le login ne sont plus spécifiés dans deux variables mais dans un unique filtre à présent. Ce qui permettra d'affiner les requêtes.

Paramètre Valeur par défaut Description
ldap.user.baseDn ou=people,dc=ejnserver,dc=fr Base de recherche pour les utilisateurs.
ldap.user.request (&(objectClass=inetOrgPerson)(uid={login})) Nouvelle propriété permettant de spécifier la requête pour identifier les utilisateurs.

{login} sera remplacé par le login utilisé lors de l'authentification. Cette nouvelle forme permet de mettre en place des filtres, de type memberOf, ce qui peut être pratique pour filtrer les utilisateurs.

ldap.user.objectClass inetOrgPerson Argument déprécié depuis la version 1.2.
ldap.user.loginAttribute uid Argument déprécié depuis la version 1.2.
ldap.user.realNameAttribute cn Propriété dans l'annuaire LDAP correspondant au nom complet de l'utilisateur.
ldap.user.emailAttribute mail Propriété dans l'annuaire LDAP correspondant au mail de l'utilisateur.

Une configuration de mapping des groupes est également mis en place, sur le même principe que les utilisateurs.

Paramètre Valeur Description
ldap.group.baseDn ou=groups,dc=ejnserver,dc=fr Base de recherche pour les groupes.
ldap.group.request (&(objectClass=groupOfNames)(member={dn})) Requête pour identifier les groupes. La valeur par défaut '(&(objectClass=group)(member={dn}))' a été modifiée pour prendre en compte les spécificités des groupes pris en compte.
ldap.group.objectClass groupOfUniqueNames Argument déprécié depuis la version 1.2.
ldap.group.idAttribute cn Propriété dans l'annuaire LDAP correspondant à l'identifiant du groupe.
ldap.group.memberAttribute uniqueMember Argument déprécié depuis la version 1.2.

Attention, il existe deux pré requis pour le bon fonctionnement du mapping des groupes.

  • Les groupes ne peuvent pas être dynamiques, ils doivent être statiques.
  • Les utilisateurs doivent avoir la propriété memberOf. Dans le cadre de l'utilisation de OpenLDAP, il est donc nécessaire d'installer l'overlay memberOf.


Les modifications sont donc assez importante et le fichier subit de nombreuses modifications.


Update icon.png Mise à jour version 1.4

Lors de l'installation du |service de SonarQube, le fichier de configuration a été revu. Le format du fichier est légèrement différent, le séparateur entre clé et valeur étant le caractère = et non plus :. Cela était peut être le cas sur de précédente version, mais la mise à jour a été réalisée lors de cette manipulation. De plus, le contenu du fichier est allégé, pour s'éviter tout un tas de commentaires qui sont finalement inutiles, et pour supprimer des paramètres dont la valeur par défaut correspond à l'implémentation réalisée.

La sécurité est déléguée à l'annuaire LDAP avec les paramètres suivants.

Paramètre Valeur par défaut Description
sonar.security.realm LDAP Délégation de l'authentification à une annuaire LDAP.
ldap.url ldap://localhost:389 URL d'accès à l'annuaire.

Dans le cadre de cette installation, il se situe sur la même machine que SonarQube.

Une configuration de mapping des utilisateurs est mis en place.

Paramètre Valeur par défaut Description
ldap.user.baseDn ou=people,dc=ejnserver,dc=fr Base de recherche pour les utilisateurs.
ldap.user.request (&(objectClass=inetOrgPerson)(uid={login})) Permet de spécifier la requête pour identifier les utilisateurs.

{login} sera remplacé par le login utilisé lors de l'authentification. Cette forme permet de mettre en place des filtres, de type memberOf, ce qui peut être pratique pour filtrer les utilisateurs.

ldap.user.realNameAttribute cn Propriété dans l'annuaire LDAP correspondant au nom complet de l'utilisateur.
ldap.user.emailAttribute mail Propriété dans l'annuaire LDAP correspondant au mail de l'utilisateur.

Une configuration de mapping des groupes est également mis en place, sur le même principe que les utilisateurs.

Paramètre Valeur Description
ldap.group.baseDn ou=groups,dc=ejnserver,dc=fr Base de recherche pour les groupes.
ldap.group.request (&(objectClass=groupOfNames)(member={dn})) Requête pour identifier les groupes. La valeur par défaut '(&(objectClass=group)(member={dn}))' a été modifiée pour prendre en compte les spécificités des groupes pris en compte.

Attention, il existe deux pré requis pour le bon fonctionnement du mapping des groupes.

  • Les groupes ne peuvent pas être dynamiques, ils doivent être statiques.
  • Les utilisateurs doivent avoir la propriété memberOf. Dans le cadre de l'utilisation de OpenLDAP, il est donc nécessaire d'installer l'overlay memberOf.


Icon-log.png Configuration des logs

Attention, Ceci ne s'applique pas pour la version 4.4 de SonarQuabe.

Comme mentionné au fil de cet article, l'utilisation du plugin peut engendrer des difficultés de connexion en cas d'incohérence de paramétrage, ce qui rend assez complexe l'analyse. Toutefois, il est possible de configurer les logs (log4j) spécifiquement pour ce plugin, et ainsi voir les différentes requêtes LDAP exécutées.

Icon-Configuration-Settings.png Configuration

La configuration est très simple pour toute personne ayant déjà travaillé avec Log4j. Il suffit de configurer le niveau de log pour le paquet org.sonar.plugins.ldap. Afin d'avoir un maximum d'information, il faut positionner le niveau à DEBUG.

Le fichier de configuration logback.xml se situe dans le répertoire SONAR_HOME/conf, soit /var/opt/sonar/conf/logback.xml dans le cadre de cette installation.

Les modifications de ce fichiers sont:

<?xml version="1.0" encoding="UTF-8" ?>

<configuration debug="false">

  <appender name="SONAR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <File>${SONAR_HOME}/logs/sonar.log</File>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <param name="FileNamePattern" value="${SONAR_HOME}/logs/sonar.%i.log"/>
      <param name="MinIndex" value="1"/>
      <param name="MaxIndex" value="3"/>
    </rollingPolicy>
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <param name="MaxFileSize" value="5MB"/>
    </triggeringPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>
        %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n
      </pattern>
    </encoder>
  </appender>

  <!-- appender used to profile Sonar Server -->
  <appender name="PROFILING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <File>${SONAR_HOME}/logs/profiling.log</File>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <param name="FileNamePattern" value="${SONAR_HOME}/logs/profiling.%i.log"/>
      <param name="MinIndex" value="1"/>
      <param name="MaxIndex" value="3"/>
    </rollingPolicy>
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <param name="MaxFileSize" value="5MB"/>
    </triggeringPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
      <pattern>
        %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n
      </pattern>
    </encoder>
  </appender>

    <!--
    Profiling of HTTP requests. Set level to DEBUG in order to log all the HTTP and SQL requests.
    Example of command-line to get the HTTP requests with execution time greater than 10s :
    grep 'rails  Completed in [0-9]\{5,\}ms' < profiling.log
   -->
  <logger name="rails"  additivity="false">
    <level value="WARN"/>
    <appender-ref ref="PROFILING_FILE"/>
  </logger>


  <logger name="org.hibernate.cache.ReadWriteCache">
    <!-- removing "An item was expired by the cache while it was locked (increase your cache timeout)" msg -->
    <level value="ERROR"/>
  </logger>
  <logger name="org.hibernate.cache.EhCacheProvider">
    <!-- removing "org.hibernate.cache.EhCacheProvider - Could not find configuration)" message -->
    <level value="ERROR"/>
  </logger>

  <!-- set DEBUG to activate Hibernate SQL logs. NOT RECOMMENDED  -->
  <logger name="org.hibernate.SQL">
    <level value="ERROR"/>
  </logger>

  <logger name="org.hibernate">
    <level value="WARN"/>
  </logger>

  <logger name="org.sonar.plugins.ldap">
    <level value="DEBUG"/>
  </logger>

  <root>
    <level value="INFO"/>
    <appender-ref ref="SONAR_FILE"/>
  </root>

</configuration>

Dans cette configuration, seul le noeud level est configuré au niveau le plus fin, DEBUG. Le noeud appender-ref n'est pas spécifié, héritant automatiquement de la configuration mise en place pour root. Ainsi les messages de log sont mis en place dans la sortie référencée par SONAR_FILE, soit ${SONAR_HOME}/logs/sonar.log.

Viewer icon.png Rendu

Avec ce niveau, il est possible de visualiser la validation de l'authentification et la récupération des groupes de l'utilisateur lors de la connexion.

Lors d'une authentification en échec, le message Password not valid for user permet de valider qu'il s'agit d'une erreur de saisie de mot de passe.

2012.04.28 21:01:53 DEBUG o.s.p.l.LdapSearch  Search: LdapSearch{baseDn=ou=people,dc=ejnserver,dc=fr, scope=subtree, request=(&
(objectClass=inetOrgPerson)(uid={0})), parameters=[etienne], attributes=[mail, cn]}
2012.04.28 21:01:53 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=admin,dc=ejnserver,dc=fr, 
com.sun.jndi.ldap.connect.pool=true, java.naming.security.authentication=simple, java.naming.referral=follow}
2012.04.28 21:01:53 DEBUG o.s.p.l.LdapSearch  Search: LdapSearch{baseDn=ou=people,dc=ejnserver,dc=fr, scope=subtree, request=(&
(objectClass=inetOrgPerson)(uid={0})), parameters=[etienne], attributes=null}
2012.04.28 21:01:53 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=admin,dc=ejnserver,dc=fr, 
com.sun.jndi.ldap.connect.pool=true, java.naming.security.authentication=simple, java.naming.referral=follow}
2012.04.28 21:01:53 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, 
java.naming.security.principal=uid=etienne,ou=people,dc=ejnserver,dc=fr, java.naming.security.authentication=simple, 
java.naming.referral=follow}
2012.04.28 21:01:53 DEBUG o.s.p.l.LdapAuthenticator  Password not valid for user uid=etienne,ou=people,dc=ejnserver,dc=fr: [LDAP: 
error code 49 - Invalid Credentials]

Sur cette trace, les requêtes de recherche de l'utilisateur dans l'annuaire sont visibles, permettant de valider les paramétrages mis en place, objectClass, baseDn ...


Lors d'une authentification réussie, les informations seront beaucoup plus riches. Les requêtes de recherche de l'utilisateur sont disponibles, comme dans le précédent exemple.

2012.04.28 21:05:45 DEBUG o.s.p.l.LdapUsersProvider  Requesting details for user etienne
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapSearch  Search: LdapSearch{baseDn=ou=people,dc=ejnserver,dc=fr, scope=subtree, request=(&
(objectClass=inetOrgPerson)(uid={0})), parameters=[etienne], attributes=[mail, cn]}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=admin,dc=ejnserver,dc=fr, 
com.sun.jndi.ldap.connect.pool=true, java.naming.security.authentication=simple, java.naming.referral=follow}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapSearch  Search: LdapSearch{baseDn=ou=people,dc=ejnserver,dc=fr, scope=subtree, request=(&
(objectClass=inetOrgPerson)(uid={0})), parameters=[etienne], attributes=null}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=admin,dc=ejnserver,dc=fr, 
com.sun.jndi.ldap.connect.pool=true, java.naming.security.authentication=simple, java.naming.referral=follow}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, 
java.naming.security.principal=uid=etienne,ou=people,dc=ejnserver,dc=fr, java.naming.security.authentication=simple, 
java.naming.referral=follow}

Les recherches des groupes d'appartenance de l'utilisateur sont également consultables.

2012.04.28 21:05:45 DEBUG o.s.p.l.LdapGroupsProvider  Requesting groups for user etienne
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapSearch  Search: LdapSearch{baseDn=ou=people,dc=ejnserver,dc=fr, scope=subtree, request=(&
(objectClass=inetOrgPerson)(uid={0})), parameters=[etienne], attributes=null}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=admin,dc=ejnserver,dc=fr, 
com.sun.jndi.ldap.connect.pool=true, java.naming.security.authentication=simple, java.naming.referral=follow}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapSearch  Search: LdapSearch{baseDn=ou=groups,dc=ejnserver,dc=fr, scope=subtree, request=(&
(objectClass=groupOfNames)(member={0})), parameters=[uid=etienne,ou=people,dc=ejnserver,dc=fr], attributes=[cn]}
2012.04.28 21:05:45 DEBUG o.s.p.l.LdapContextFactory  Initializing LDAP context {java.naming.provider.url=ldap://localhost:389, 
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory, java.naming.security.principal=cn=admin,dc=ejnserver,dc=fr, 
com.sun.jndi.ldap.connect.pool=true, java.naming.security.authentication=simple, java.naming.referral=follow}


Warning-icon.png Configuration Iptables

Dans le cadre de la mise en place de restriction Iptables, si l'adresse IP du serveur, même en local, n'est pas authorisée à accéder à l'annuaire, il était devenu impossible de se connecter sur des application comme Jenkins, Nexus ou Subsonic. Dans le cadre de Sonar, le problème de connexion ne s'est pas produit.


Viewer icon.png Voir aussi

Documentation officielle: http://docs.sonarqube.org/display/PLUG/LDAP+Plugin