Sonar Configuration LDAP
Sommaire
Votre avis
Current user rating: 85/100 (1 votes)
|
|
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.
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.
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.
#-------------------
# Sonar LDAP Plugin
#-------------------
# IMPORTANT : before activation, make sure that one Sonar administrator is defined in the external system
# Activates the plugin. Leave blank or comment out to use default sonar authentication.
sonar.authenticator.class: org.sonar.plugins.ldap.LdapAuthenticator
# Ignore failure at startup if the connection to external system is refused.
# Users can browse sonar but not log in as long as the connection fails.
# When set to true, Sonar will not start if connection to external system fails.
# Default is false.
#sonar.authenticator.ignoreStartupFailure: true
# Automatically create users (available since Sonar 2.0).
# When set to true, user will be created after successful authentication, if doesn't exists.
# The default group affected to new users can be defined online, in Sonar general settings. The default value is "sonar-users".
# Default is false.
#sonar.authenticator.createUsers: true
# (omit if you use autodiscovery) URL of the LDAP server.
# If you are using ldaps, then you should install server certificate into java truststore.
# eg. ldap://localhost:10389
ldap.url: ldap://localhost:389
# (optional) Distinguished Name (DN) of the root node in LDAP from which to search for users,
# eg. “ou=users,o=mycompany”
ldap.baseDn: ou=people,dc=ejnserver,dc=fr
# (optional) Bind DN is the username of an LDAP user to connect (or bind) with.
# This is a Distinguished Name of a user who has administrative rights,
# eg. “cn=sonar,ou=users,o=mycompany”. Leave blank for anonymous access to the LDAP directory.
#ldap.bindDn:
ldap.bindDn: cn=admin,dc=ejnserver,dc=fr
# (optional) Bind Password is the password of the user to connect with.
# Leave blank for anonymous access to the LDAP directory.
#ldap.bindPassword:
ldap.bindPassword: ADMIN_PASSWORD
# (optional) Login Attribute is the attribute in LDAP holding the user’s login.
# Default is ‘uid’. Set ’sAMAccountName’ for Microsoft Active Directory
#ldap.loginAttribute: sAMAccountName
# (optional) Object class of LDAP users.
# Default is 'inetOrgPerson'. Set ‘user’ for Microsoft Active Directory.
#ldap.userObjectClass: user
# (advanced option) See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html
# Default is 'simple'. Possible values: 'simple', 'CRAM-MD5', 'DIGEST-MD5', 'GSSAPI'.
#ldap.authentication: DIGEST-MD5
# (advanced option)
# See
# http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html
# http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html
# eg. example.org
#ldap.realm:
# (advanced option) Context factory class.
# Default is 'com.sun.jndi.ldap.LdapCtxFactory'.
#ldap.contextFactoryClass: com.sun.jndi.ldap.LdapCtxFactory
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.
#-------------------
# Sonar LDAP Plugin
#-------------------
# IMPORTANT : before activation, make sure that one Sonar administrator is defined in the external system
# Activates the plugin. Leave blank or comment out to use default sonar authentication.
sonar.authenticator.class: org.sonar.plugins.ldap.LdapAuthenticator
# Ignore failure at startup if the connection to external system is refused.
# Users can browse sonar but not log in as long as the connection fails.
# When set to true, Sonar will not start if connection to external system fails.
# Default is false.
sonar.authenticator.ignoreStartupFailure: true
# Automatically create users (available since Sonar 2.0).
# When set to true, user will be created after successful authentication, if doesn't exists.
# The default group affected to new users can be defined online, in Sonar general settings. The default value is "sonar-users".
# Default is false.
#sonar.authenticator.createUsers: true
# (omit if you use autodiscovery) URL of the LDAP server.
# If you are using ldaps, then you should install server certificate into java truststore.
# eg. ldap://localhost:10389
ldap.url: ldap://localhost:389
# (optional) Distinguished Name (DN) of the root node in LDAP from which to search for users,
# eg. “ou=users,o=mycompany”
ldap.baseDn: ou=people,dc=ejnserver,dc=fr
# (optional) Bind DN is the username of an LDAP user to connect (or bind) with.
# This is a Distinguished Name of a user who has administrative rights,
# eg. “cn=sonar,ou=users,o=mycompany”. Leave blank for anonymous access to the LDAP directory.
#ldap.bindDn:
ldap.bindDn: cn=admin,dc=ejnserver,dc=fr
# (optional) Bind Password is the password of the user to connect with.
# Leave blank for anonymous access to the LDAP directory.
#ldap.bindPassword:
ldap.bindPassword: ADMIN_PASSWORD
# Login Attribute is the attribute in LDAP holding the user’s login.
# Default is ‘uid’. Set ’sAMAccountName’ for Microsoft Active Directory
#ldap.loginAttribute: sAMAccountName
# Object class of LDAP users.
# Default is 'inetOrgPerson'. Set ‘user’ for Microsoft Active Directory.
#ldap.userObjectClass: user
# (advanced option) See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html
# Default is 'simple'. Possible values: 'simple', 'CRAM-MD5', 'DIGEST-MD5', 'GSSAPI'.
#ldap.authentication: DIGEST-MD5
# (advanced option)
# See
# http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html
# http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html
# eg. example.org
#ldap.realm:
# (advanced option) Context factory class.
# Default is 'com.sun.jndi.ldap.LdapCtxFactory'.
#ldap.contextFactoryClass: com.sun.jndi.ldap.LdapCtxFactory
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 | 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.
2012.04.28 10:06:54 ERROR o.s.s.p.Platform Fail to start server org.sonar.api.utils.SonarException: Authenticator 'org.sonar.plugins.ldap.LdapAuthenticator' not found. Please check the property 'sonar.authenticator.class' in conf/sonar.properties at org.sonar.server.ui.SecurityRealmFactory.<init>(SecurityRealmFactory.java:58) ~[SecurityRealmFactory.class:na] at org.sonar.server.ui.SecurityRealmFactory.<init>(SecurityRealmFactory.java:71) ~[SecurityRealmFactory.class:na] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.6.0_26] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) ~[na:1.6.0_26] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) ~[na:1.6.0_26] at java.lang.reflect.Constructor.newInstance(Constructor.java:513) ~[na:1.6.0_26] at org.picocontainer.injectors.AbstractInjector.newInstance(AbstractInjector.java:147) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.injectors.ConstructorInjector$1.run(ConstructorInjector.java:348) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.injectors.AbstractInjector$ThreadLocalCyclicDependencyGuard.observe(AbstractInjector.java:272) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.injectors.ConstructorInjector.getComponentInstance(ConstructorInjector.java:370) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.injectors.AbstractInjectionFactory$LifecycleAdapter.getComponentInstance(AbstractInjectionFactory.java:56) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.behaviors.AbstractBehavior.getComponentInstance(AbstractBehavior.java:64) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.behaviors.Stored.getComponentInstance(Stored.java:91) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.DefaultPicoContainer.instantiateComponentAsIsStartable(DefaultPicoContainer.java:1027) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.DefaultPicoContainer.addAdapterIfStartable(DefaultPicoContainer.java:1019) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.DefaultPicoContainer.startAdapters(DefaultPicoContainer.java:996) ~[picocontainer-2.14.1.jar:na] at org.picocontainer.DefaultPicoContainer.start(DefaultPicoContainer.java:760) ~[picocontainer-2.14.1.jar:na] at org.sonar.api.platform.ComponentContainer.startComponents(ComponentContainer.java:70) ~[sonar-plugin-api-2.14.jar:na] at org.sonar.server.platform.Platform.startServiceComponents(Platform.java:219) ~[Platform.class:na] at org.sonar.server.platform.Platform.start(Platform.java:115) ~[Platform.class:na] at org.sonar.server.platform.PlatformLifecycleListener.contextInitialized(PlatformLifecycleListener.java:34) [PlatformLifecycleListener.class:na] at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:675) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:601) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1315) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1061) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.StandardHost.start(StandardHost.java:840) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.StandardService.start(StandardService.java:525) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.core.StandardServer.start(StandardServer.java:754) [catalina-6.0.32.jar:6.0.32] at org.apache.catalina.startup.Catalina.start(Catalina.java:595) [catalina-6.0.32.jar:6.0.32] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_26] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_26] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_26] at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_26] at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289) [bootstrap.jar:6.0.32] at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414) [bootstrap.jar:6.0.32] 2012.04.28 10:07:15 INFO org.sonar.INFO Loading webservice /api/plugins/MotionchartWebService 2012.04.28 10:07:16 INFO org.sonar.INFO Stop sonar... 2012.04.28 10:07:16 INFO org.sonar.INFO Stop sonar done: 14 ms
Les modifications sont donc assez importante et le fichier subit de nombreuses modifications.
#-------------------
# Sonar LDAP Plugin
#-------------------
# IMPORTANT : before activation, make sure that one Sonar administrator is defined in the external system
# Activates the plugin. Leave blank or comment out to use default sonar authentication.
# For plugin version 1.0
#sonar.authenticator.class: org.sonar.plugins.ldap.LdapAuthenticator
# For plugin version 1.1.1
sonar.security.realm: LDAP
# Ignore failure at startup if the connection to external system is refused.
# Users can browse sonar but not log in as long as the connection fails.
# When set to true, Sonar will not start if connection to external system fails.
# Default is false.
#sonar.authenticator.ignoreStartupFailure: true
# Automatically create users (available since Sonar 2.0).
# When set to true, user will be created after successful authentication, if doesn't exists.
# The default group affected to new users can be defined online, in Sonar general settings. The default value is "sonar-users".
# Default is false.
sonar.authenticator.createUsers: true
# (omit if you use autodiscovery) URL of the LDAP server.
# If you are using ldaps, then you should install server certificate into java truststore.
# eg. ldap://localhost:10389
ldap.url: ldap://localhost:389
# (optional) Distinguished Name (DN) of the root node in LDAP from which to search for users,
# eg. 'ou=users,o=mycompany'
# For plugin version 1.0
#ldap.baseDn: ou=people,d0c=ejnserver,dc=fr
# For plugin version 1.1.1
ldap.user.baseDn: ou=people,dc=ejnserver,dc=fr
# (optional) Bind Password is the password of the user to connect with.
# Leave blank for anonymous access to the LDAP directory.
#ldap.bindPassword:
ldap.bindPassword: ADMIN_PASSWORD
# (optional) Bind DN is the username of an LDAP user to connect (or bind) with.
# This is a Distinguished Name of a user who has administrative rights,
# eg. 'cn=sonar,ou=users,o=mycompany'. Leave blank for anonymous access to the LDAP directory.
#ldap.bindDn:
ldap.bindDn: cn=admin,dc=ejnserver,dc=fr
# (optional) Login Attribute is the attribute in LDAP holding the user's login.
# Default is 'uid'. Set 'sAMAccountName' for Microsoft Active Directory
# For plugin version 1.0
#ldap.loginAttribute: sAMAccountName
# For plugin version 1.1.1
#ldap.user.loginAttribute: sAMAccountName
# (optional) Email Attribute is the attribute in LDAP holding the user's mail.
# Default is 'mail'.
# For plugin version 1.1.1
#ldap.user.emailAttribute: mail
# (optional) Real Name Attribute is the attribute in LDAP holding the user's name.
# Default is 'cn'.
# For plugin version 1.1.1
#ldap.user.realNameAttribute: cn
# Object class of LDAP users.
# Default is 'inetOrgPerson'. Set 'user' for Microsoft Active Directory.
# For plugin version 1.0
#ldap.userObjectClass: user
# For plugin version 1.1.1
#ldap.user.objectClass: user
# (advanced option) See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html
# Default is 'simple'. Possible values: 'simple', 'CRAM-MD5', 'DIGEST-MD5', 'GSSAPI'.
#ldap.authentication: DIGEST-MD5
# (advanced option)
# See
# http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html
# http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html
# eg. example.org
#ldap.realm:
# (advanced option) Context factory class.
# Default is 'com.sun.jndi.ldap.LdapCtxFactory'.
#ldap.contextFactoryClass: com.sun.jndi.ldap.LdapCtxFactory
# (mandatory) Distinguished Name (DN) of the root node in LDAP from which to search for groups,
# eg. 'ou=groups,o=mycompany'
# For plugin version 1.1.1
ldap.group.baseDn: ou=groups,dc=ejnserver,dc=fr
# (optional) Object class of LDAP groups.
# Default is 'groupOfUniqueNames'. Set 'group' for Microsoft Active Directory.
# For plugin version 1.1.1
#ldap.group.objectClass: groupOfUniqueNames
ldap.group.objectClass: groupOfNames
# (optional) Attribute in LDAP holding the group's id.
# Default is 'cn'.
# For plugin version 1.1.1
#ldap.group.idAttribute: cn
# (optional) Attribute in LDAP holding the group's member.
# Default is 'uniqueMember'. Set 'member' for Microsoft Active Directory.
# For plugin version 1.1.1
#ldap.group.memberAttribute: uniqueMember
ldap.group.memberAttribute: member
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. |
inetOrgPerson | Argument déprécié depuis la version 1.2. | |
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 | 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. |
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. |
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.
#-------------------
# Sonar LDAP Plugin
#-------------------
# IMPORTANT : before activation, make sure that one Sonar administrator is defined in the external system
# Activates the plugin. Leave blank or comment out to use default sonar authentication.
# For plugin version 1.0
#sonar.authenticator.class: org.sonar.plugins.ldap.LdapAuthenticator
# For plugin version 1.1.1
sonar.security.realm: LDAP
# Ignore failure at startup if the connection to external system is refused.
# Users can browse sonar but not log in as long as the connection fails.
# When set to true, Sonar will not start if connection to external system fails.
# Default is false.
#sonar.authenticator.ignoreStartupFailure: true
# Automatically create users (available since Sonar 2.0).
# When set to true, user will be created after successful authentication, if doesn't exists.
# The default group affected to new users can be defined online, in Sonar general settings. The default value is "sonar-users".
# Default is false.
sonar.authenticator.createUsers: true
# (omit if you use autodiscovery) URL of the LDAP server.
# If you are using ldaps, then you should install server certificate into java truststore.
# eg. ldap://localhost:10389
ldap.url: ldap://localhost:389
# (optional) Distinguished Name (DN) of the root node in LDAP from which to search for users,
# eg. 'ou=users,o=mycompany'
# For plugin version 1.0
#ldap.baseDn: ou=people,d0c=ejnserver,dc=fr
# For plugin version 1.1.1
ldap.user.baseDn: ou=people,dc=ejnserver,dc=fr
# (optional) Bind Password is the password of the user to connect with.
# Leave blank for anonymous access to the LDAP directory.
#ldap.bindPassword:
ldap.bindPassword: GCW5E5S8LdapAdmin
# (optional) Bind DN is the username of an LDAP user to connect (or bind) with.
# This is a Distinguished Name of a user who has administrative rights,
# eg. 'cn=sonar,ou=users,o=mycompany'. Leave blank for anonymous access to the LDAP directory.
#ldap.bindDn:
ldap.bindDn: cn=admin,dc=ejnserver,dc=fr
# (optional) Login Attribute is the attribute in LDAP holding the user's login.
# Default is 'uid'. Set 'sAMAccountName' for Microsoft Active Directory
# For plugin version 1.0
#ldap.loginAttribute: sAMAccountName
# For plugin version 1.1.1 deprecated since version 1.2
#ldap.user.loginAttribute: sAMAccountName
# (optional) Email Attribute is the attribute in LDAP holding the user's mail.
# Default is 'mail'.
# For plugin version 1.1.1
#ldap.user.emailAttribute: mail
# (optional) Real Name Attribute is the attribute in LDAP holding the user's name.
# Default is 'cn'.
# For plugin version 1.1.1
#ldap.user.realNameAttribute: cn
# Object class of LDAP users.
# Default is 'inetOrgPerson'. Set 'user' for Microsoft Active Directory.
# For plugin version 1.0
#ldap.userObjectClass: user
# For plugin version 1.1.1 deprecated since version 1.2
#ldap.user.objectClass: user
# LDAP query to identify user, since 1.2.
# Default is '(&(objectClass=inetOrgPerson)(uid={login}))'.
# Set '(&(objectClass=user)(sAMAccountName={login}))' for Microsoft Active Directory.
#ldap.user.request: (&(objectClass=inetOrgPerson)(uid={login}))
# (advanced option) See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html
# Default is 'simple'. Possible values: 'simple', 'CRAM-MD5', 'DIGEST-MD5', 'GSSAPI'.
#ldap.authentication: DIGEST-MD5
# (advanced option)
# See
# http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html
# http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html
# eg. example.org
#ldap.realm:
# (advanced option) Context factory class.
# Default is 'com.sun.jndi.ldap.LdapCtxFactory'.
#ldap.contextFactoryClass: com.sun.jndi.ldap.LdapCtxFactory
# (mandatory) Distinguished Name (DN) of the root node in LDAP from which to search for groups,
# eg. 'ou=groups,o=mycompany'
# For plugin version 1.1.1
ldap.group.baseDn: ou=groups,dc=ejnserver,dc=fr
# LDAP query to identify group, since 1.2.
# Default is '(&(objectClass=groupOfUniqueNames)(uniqueMember={dn}))'.
# Set '(&(objectClass=group)(member={dn}))' for Microsoft Active Directory.
ldap.group.request: (&(objectClass=groupOfNames)(member={dn}))
# (optional) Object class of LDAP groups.
# Default is 'groupOfUniqueNames'. Set 'group' for Microsoft Active Directory.
# For plugin version 1.1.1, deprecated since 1.2
#ldap.group.objectClass: groupOfUniqueNames
#ldap.group.objectClass: groupOfNames
# (optional) Attribute in LDAP holding the group's id.
# Default is 'cn'.
# For plugin version 1.1.1
#ldap.group.idAttribute: cn
# (optional) Attribute in LDAP holding the group's member.
# Default is 'uniqueMember'. Set 'member' for Microsoft Active Directory.
# For plugin version 1.1.1, deprecated since 1.2
#ldap.group.memberAttribute: uniqueMember
#ldap.group.memberAttribute: member
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 | 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.
#--------------------------------------------------------------------------------------------------
# LDAP Configuration
# General Configuration
sonar.security.realm=LDAP
ldap.url=ldap://localhost:389
# User Configuration
ldap.user.baseDn=ou=people,dc=ejnserver,dc=fr
ldap.user.request=(uid={login})
ldap.user.realNameAttribute=cn
ldap.user.emailAttribute=mail
# Group Configuration
ldap.group.baseDn=ou=groups,dc=ejnserver,dc=fr
ldap.group.request=(&(objectClass=groupOfNames)(member={dn}))
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.
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
.
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}
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 autorisé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.
Voir aussi
Documentation officielle: http://docs.sonarqube.org/display/PLUG/LDAP+Plugin