jeudi 8 décembre 2011

Struts2 : Utilisation des attributs dans la méthode prepare()

Lorsque vous souhaitez initialiser certains attributs de votre action Struts 2 en fonction des données saisies par l'utilisateur, telles que des listes déroulantes par exemple, votre action doit implémenter l'interface Preparable. Ainsi, avant chaque appel d'une méthode de votre action, la méthode prepare() est appelée.

public class MonAction extends ActionSupport implements Preparable {
    ...
        public void prepare() {
              // En fonction des attributs recus, initialiser ici les attributs de votre action qui seront transmis à votre vue
        }
}
D'après la documentation officielle de Struts 2, pour utiliser la méthode prepare(), il faut aussi utiliser l'interceptor prepare correspondant dans votre struts.xml.
De plus, pour que les attributs soient disponibles dans prepare(), l'astuce consiste en fait à ré appeler l'interceptor params avant prepare, comme indiqué ci-dessous :

<!-- Calls the params interceptor twice, allowing you to
      pre-load data for the second time parameters are set -->
 <action name="someAction" class="com.examples.SomeAction">
     <interceptor-ref name="params"/>
     <interceptor-ref name="prepare"/>
     <interceptor-ref name="basicStack"/>
     <result name="success">good_result.ftl</result>
 </action>


Mais si vos vues contiennent des checkbox,  cela n'est pas suffisant. Cela provoque en effet une erreur du genre :
OgnlValueStac W com.opensymphony.xwork2.util.logging.commons.CommonsLogger warn Error setting expression '__checkbox_xxxx' with value '[Ljava.lang.String;@1f7c9ad'
ognl.OgnlException: target is null for setProperty(null, "xxxx", [Ljava.lang.String;@1f7c9ad)

Pour résoudre ce problème, il faut en fait aussi utiliser l'interceptor checkbox en double

<action name="someAction" class="com.examples.SomeAction">
     <interceptor-ref name="checbox"/>
     <interceptor-ref name="params"/>
     <interceptor-ref name="prepare"/>
     <interceptor-ref name="basicStack"/>
     <result name="success">good_result.ftl</result>
 </action>

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>");
        


vendredi 25 novembre 2011

Tomcat : Configurer le serveur en https

Voici la procédure pour configurer son Tomcat en https 

Etape 1 - Création du certificat Tomcat

C:\Program Files (x86)\Java\jdk1.6.0_13\bin>keytool -delete -alias tomcat

C:\Program Files (x86)\Java\jdk1.6.0_13\bin>keytool -list -alias tomcat
Tapez le mot de passe du Keystore : test1234

--- !!! D'apres la doc : mettre le même mot de passe pour la clé tomcat que pour le keystore !!!

C:\Program Files (x86)\Java\jdk1.6.0_13\bin>keytool -genkey -alias tomcat -keyalg RSA
Tapez le mot de passe du Keystore :
Quels sont vos prénom et nom ?
  [Unknown] :  Moi
Quel est le nom de votre unité organisationnelle ?
  [Unknown] : 
Quelle est le nom de votre organisation ?
  [Unknown] :
Quel est le nom de votre ville de résidence ?
  [Unknown] :
Quel est le nom de votre état ou province ?
  [Unknown] :
Quel est le code de pays à deux lettres pour cette unité ?
  [Unknown] :  fr
Est-ce CN=Moi, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=fr ?
  [non] :  oui

Spécifiez le mot de passe de la clé pour <tomcat>
        (appuyez sur Entrée s'il s'agit du mot de passe du Keystore) :


Etape 2 - Exporter le Certificat
C:\Program Files (x86)\Java\jdk1.6.0_13\bin>keytool -export -alias tomcat -file server-tomcat.crt

       
Etape 3 - Importer le certificat dans la jvm du Tomcat

-- Import dans la jvm du Tomcat concernée
C:\Program Files (x86)\Java\jdk1.6.0_13\bin>keytool -import -trustcacerts -keystore ..\jre\lib\security\cacerts -alias tomcat -file server-tomcat.crt

-- Note : Si d'autres jvm clientes veulent se connecter en https à ce serveur, il faudra répeter l'étape pour chaque jvm cliente

-- Lister les certificats de la jvm
C:\Program Files (x86)\Java\jdk1.6.0_13\bin>keytool -list -keystore ..\jre\lib\security\cacerts
       
       
Etape 4 - Activation du ssl dans tomcat

-- Dans le fichier server.xml, décommenter et modifier le bloc comme suit

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"  
               maxThreads="150" scheme="https" secure="true"
               keystorePass="test1234" keyalias="tomcat"
               clientAuth="false" sslProtocol="TLS" />
   
-- pour tester : https://localhost:8443/



Liens : http://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html#Configuration