vendredi 2 décembre 2011

Jasig CAS : Récupérer les attributs LDAP


Voici une précision pour configurer son serveur SSO CAS avec une athentification LDAP et récupérer des attributs LDAP dans son application caséifiée.

La doc officielle CAS n'est pas assez précise sur le sujet ni très à jour vis à vis de la dernière version  3.4.11


Configuration du serveur CAS pour une authentification LDAP

Modifier le fichier deployerConfigContext.xml comme suit.

Au niveau du handler qui gére le login/password, préciser que l'on veut s'identifier via ldap :

<property name="authenticationHandlers">
            <list>
               <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
                    p:httpClient-ref="httpClient" />
              
                <bean class="org.jasig.cas.adaptors.ldap.BindLdapAuthenticationHandler"
                  p:filter="mail=%u"
                  p:searchBase="dc=example,dc=com"
                  p:contextSource-ref="contextSource"
                  />

                
            </list>
</property>

Ici, la vérification du login/password s'effectuera via ldap avec BindLdapAuthenticationHandler.
p:filter="mail=%u" : précise que le mail est utilisé en login
p:searchBase="dc=example,dc=com" : précise la chaine de recherche dans l'annuaire ldap
p:contextSource-ref="contextSource" : précise de rechercher les infos du ldap dans le bean contextSource

La configuration du ldap est effectué comme ceci :

<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
      <property name="pooled" value="false"/>
   
      <property name="url" value="ldap://localhost" />
   
      <property name="userDn" value="cn=Directory Manager"/>
      <property name="password" value="xxxx"/>
   
      <!-- Place JNDI environment properties here. -->
      <property name="baseEnvironmentProperties">
        <map>
          <!-- Three seconds is an eternity to users. -->
          <entry key="com.sun.jndi.ldap.connect.timeout" value="3000" />
          <entry key="com.sun.jndi.ldap.read.timeout" value="3000" />
   
          <!-- Explained at http://download.oracle.com/javase/1.3/docs/api/javax/naming/Context.html#SECURITY_AUTHENTICATION -->
          <entry key="java.naming.security.authentication" value="simple" />
        </map>
      </property>
 </bean>
Avec :
url : url du ldap ((ici localhost)
userDn : login administrateur du ldap
password : mot de passe de l'administrateur du ldap


Ensuite au niveau de l'authentification, pour préciser comment récupérer les attributs, il faut ajouter :

<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >
       <property name="attributeRepository" ref="attributeRepository" />
</bean>
 Et l'on définit le repository où trouver les attributs :

<bean id="attributeRepository"  class="org.jasig.services.persondir.support.ldap.LdapPersonAttributeDao">
      <property name="contextSource" ref="contextSource" />
      <property name="baseDN" value="dc=example,dc=com" />
      <property name="requireAllQueryAttributes" value="true" />
   
      <!--
      Attribute mapping beetween principal (key) and LDAP (value) names
      used to perform the LDAP search.  By default, multiple search criteria
      are ANDed together.  Set the queryType property to change to OR.
      -->
      <property name="queryAttributeMapping">
        <map>
          <entry key="username" value="mail" />
        </map>
      </property>
   
      <property name="resultAttributeMapping">
        <map>
        <!-- Mapping beetween LDAP entry attributes (key) and Principal's (value) -->
        <entry key="cn" value="Name"/>
        <entry value="Telephone" key="telephoneNumber" />
        <entry value="Fax" key="facsimileTelephoneNumber" />
        </map>
      </property>
    </bean>
Ici le repository où CAS va aller chercher les attributs complémentaires et l'annuaire ldap lui-même. Mais il est aussi possible de lui dire d'aller chercher des attributs autre part, dans une base de données, etc...

queryAttributeMapping : permet de préciser que le mail sert de clé à la recherche dans le ldap
resultAttributeMapping : liste des attributs à récupérer du ldap (telephoneNumber et facsimileTelephoneNumber sont renommés en Telephone et Fax)


Voici la partie qui a été le plus difficile à trouver... En effet, il faut explicitement préciser pour chaque service quels attributs sont autorisés à remonter au niveau de l'application cliente...
 <bean class="org.jasig.cas.services.RegisteredServiceImpl">
                        <property name="id" value="0" />
                        <property name="name" value="HTTP" />
                        <property name="description" value="Only Allows HTTP Urls" />
                        <property name="serviceId" value="http://**" />
                        <property name="evaluationOrder" value="10000001" />
                        <property name="allowedAttributes" >
                            <list>
                                <value>Telephone</value>
                                <value>Fax</value>                                                      
                            </list>
                        </property>
</bean>

Ici allowedAttributes liste les attributs qui seront renvoyés à l'application cliente via HTTP



Configuration de l'application web java cliente

Il faut configurer la webapp afin d'utiliser le protocole SAML Pour cela modifier le fichier web.xml comme indiqué dans la documentation CAS
 
Ensuite on récupère les attributs comme ceci :

        AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
       
        Map attributes = principal.getAttributes();
       
        Iterator attributeNames = attributes.keySet().iterator();
       
        out.println("Attributs<table>");
       
        for (; attributeNames.hasNext();) {
        out.println("<tr><th>");
        String attributeName = (String) attributeNames.next();
              out.println(attributeName);
              out.println("</th><td>");
              Object attributeValue = attributes.get(attributeName);
              out.println(attributeValue);
              out.println("</td></tr>");
        }
       
        out.println("</table>");
        


3 commentaires:

  1. Croyez le ou non, votre post m'a bcp servi :)

    RépondreSupprimer
  2. Bonjour,

    Merci beaucoup pour ce super article :)
    J'ai suivi les instructions à la lettre mais je n'arrive toujours pas à transmettre les attributs.
    Pourtant je les vois dans le logs qu'ils sont bien récupérés dans notre Active Directory.

    J'utilise la version 3.4.11

    RépondreSupprimer
  3. slt je voudrai savoir si il est possible d'authentifier uniquement certains utilisateurs

    RépondreSupprimer