JAX-*S: Handlers & Filters

L'objectif de ce TP est de mettre en place des intercepteurs (handlers et filters) JAX-*S.

Les développements se feront dans le projet services du TP3. Si les services du TP3 ne sont pas pleinement fonctionnels, on pourra se contenter d'en faire une version simplifiée (e.g. sans persistance) pour les besoins de ce TP.

Rendu

Ce TP est à rendre pour le mercredi 18/11/2015. Le rendu se fera par l'intermédiaire d'un projet forge (on fera attention a bien donner au moins le rôle “reporter” à Emmanuel Coquery et à Lionel Medini) contenant:

  • le projet maven mis à jour par vos soins (sans le répertoire target)
  • un fichier README.txt contenant au moins les noms, prénoms et numéros d'étudiants du binôme. Toute autre information à transmettre aux enseignants (e.g. justifications de choix techniques) se fera dans ce fichier.

L'identifiant du projet forge (de la forme pxxxxxx-nomprojet) est à saisir dans Tomuss, dans l'UE Tiw5 WebServices, dans la case TP4_F. On fera attention à tagger la révision correspondant au rendu avec le tag TP4.

Handlers JAX-WS

Exemple

Créer une classe tiw5.restaurants.commande.handlers.SimpleLogHandler contenant le code suivant:

SimpleLogHandler.java
package tiw5.restaurants.commande.handlers;
 
import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class SimpleLogHandler implements LogicalHandler<LogicalMessageContext> {
 
	private final static Logger LOG = LoggerFactory.getLogger(SimpleLogHandler.class);
 
	@Override
	public void close(MessageContext ctx) {
	}
 
	@Override
	public boolean handleFault(LogicalMessageContext ctx) {
		LOG.warn("faute");
		return true;
	}
 
	@Override
	public boolean handleMessage(LogicalMessageContext ctx) {
		boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		LOG.info("message "+(outbound?"sortant":"entrant"));
		return true;
	}
 
}

Créer un fichier src/main/resources/tiw5/restaurants/commande/handler-chains.xml contenant:

handler-chains.xml
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
  <handler-chain>
    <handler>
      <handler-name>sw.film.vod.services.handlers.SimpleLogHandler</handler-name>
      <handler-class>sw.film.vod.services.handlers.SimpleLogHandler</handler-class>
    </handler>
    <!-- handler>
      <handler-name>un.autre.Handler</handler-name>
      <handler-class>un.autre.Handler</handler-class>
    </handler -->
  </handler-chain>
</handler-chains>

Ajouter l'annotation @HandlerChain(file="handler-chains.xml") dans la classe tiw5.restaurants.commande.CommandeServiceImpl, ou tout autre nom que vous aurez choisi pour la classe d'implémentation du service. Attention cependant au nom de package: le répertoire de handler-chains.xml correspond au nom de package de votre classe. Déployer le service et tester l'affichage dans les log en appelant le service avec SOAPUI.

Ajout d'information

Créer un nouveau handler qui récupère dans le header SOAP la valeur de l'élément client-id et l'injecte dans le contexte (propriété “client.id”). Modifier le handler de log pour afficher cette propriété si elle est présente. Ajouter ce handler dans la chaîne d'interception et modifier le test soapUI de votre service de commande pour y intégrer le nouveau header et tester.

Récupération de l'objet client et authentification

Créer un handler logique d'authentification qui ajoute une propriété client contenant un objet Client correspondant à la propriété client-id. Si le client n'existe pas, le handler interdit l'accès au service1).

Ajouter l'intercepteur dans la chaîne des services et tester. On pourra créer un ensemble de clients pour le test via un test JUnit dans le projet services en utilisant JPA, ou via toute autre méthode, e.g. utilisation de script d'init SQL, etc.

Autorisation

Créer un handler logique qui interdit l'accès à l'opération statut si idCommande (i.e. le contenu de l'élément status) ne correspond à aucune commande ou si le client de la commande n'est pas celui qui fait la demande de statut;

Débit du compte client

Ajouter un champ double valeurCompte dans la classe Client.

Modifier l'API du service (DTO DemandeCommande et commande.xsd) de façon à supprimer le champ idClient.

Ajouter un champ de type javax.xml.ws.WebServiceContext dans la classe d'implémentation du service. Annoter ce champ avec @Resource afin que le contexte soit injecté via IoC. La méthode getMessageContext() permet alors de récupérer le contexte du message et les propriétés qui ont été ajoutées par les handlers. Modifier le code métier du service pour:

  1. récupérer l'objet Client depuis le contexte
  2. débiter le compte du client

<note tip>Seules les propriétés dont le scope est MessageContext.Scope.APPLICATION peuvent être accédées dans le bean qui code le service. Il faut donc penser à changer le scope de la propriété client dans le handler d'authentification via

ctx.setScope("client", Scope.APPLICATION);

</note>

Filters JAX-RS

On souhaite sécuriser la ressource REST Client. Utiliser l'API Filters de JAX-RS pour vérifier la présence du login lechef et du mot de passe cesttresbon dans les headers de la requête pour toute modification des menus et/ou des plats.

1)
normalement, il faudrait aussi vérifier un mot de passe ici