Si vous aussi vous luttez pour créer des Webservices sécurisés, voici quelques astuces que j'ai découvertes au fur et à mesures de mes pérégrinations. Je mettrai à jour ce billet dès que je découvre de nouveaux trucs. À ce jour, je ne parle que de la partie client.
J'utilise ici Apache CXF 3.0.4 et Spring 3.1.13.RELEASE.
Mon objectif est de parvenir à tout configurer via la applicationContext.xml (à en coder le moins possible !).
D'abord, ce qu'il faut comprendre, c'est que Apache CXF utilise des intercepteurs afin de sécuriser les Webservices.
Qu'est-ce qu'un intercepteur ? Il s'agit d'un processus qui va récupérer une requête que l'on souhaite envoyer et réaliser une action dessus.
Cette action peut être soit de rajouter/supprimer/modifier des éléments de la requête, soit de la logger, etc.
Comment rajouter des intercepteurs ?
Il suffit de rajouter les classes d'intercepteur dans les listes d'intercepteurs de requêtes entrantes (inInterceptor) ou sortantes (outInterceptor)
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="serviceType" /> <property name="address" value="http://adresse" /> <property name="inInterceptors"> <list> <ref bean="logIn" /> <ref bean="signResponse" /> </list> </property> <property name="outInterceptors"> <list> <ref bean="logOut" /> <ref bean="saajOut" /> <ref bean="signRequest" /> </list> </property> </bean> |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <bean id="signRequest" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken Timestamp Signature Encrypt" /> <entry key="user" value="laurent" /> <entry key="passwordType" value="PasswordText" /> <entry key="signatureUser" value="serverwsalias" /> <entry key="encryptionUser" value="serverwsalias" /> <entry key="passwordCallbackClass" value="main.ClientPasswordCallback" /> <entry key="signaturePropFile" value="/crypt.properties"></entry> <entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;Body" /> <entry key="encryptionPropFile" value="/crypt.properties"></entry> <entry key="encryptionParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}UsernameToken;Body" /> </map> </constructor-arg> </bean> |
Dans les actions, on définit les différentes actions que devra réaliser l'intercepteur. Ici, on a UsernameToken (authentification par username/mot de passe), Timestamp (la date de création et d'expiration de la requête va être indiquée), Signature (on va signer le message afin d'assurer l'identité de l’émetteur) et Encrypt (on va crypter la requête).
L'ordre a une importance ! les actions a b c d seront dans la requêtes sous la forme
Code : | Sélectionner tout |
1 2 3 4 5 6 | <header> <d>…</d> <c>…</c> <b>…</b> <a>…</a> </header> |
- Si "signatureUser" n'est pas spécifier, il utilisera la valeur de "user"
- pour "passwordCallbackClass", on doit créer une classe qui implémente la classe CallbackHandler afin de donner un mode passe pour un user donné. CXF s'occupe ensuite de comparer.
- Pour "signatureParts" et "encryptionParts", il faut spécifier les différents éléments de la requêtes XML qui seront signés ou crypter, séparé par un ";". Il se construise de la façon suivante : {Element}{adresse du xsd qui définit l'attribut XML}Id_de_l'attribut.
Voilà, j'espère que ça pourra aider certaines personnes.