vendredi 20 mai 2011

Client WCF et HTTP Basic Authentification

WCF propose 2 protocoles pour cela : BasicHttpBinding et WSHttpBinding avec des caractéristiques différentes. Parmi celles-ci, la version SOAP des messages échangés doit être de version SOAP 1.1 pour  BasicHttpBinding et SOAP 1.2 pour WSHttpBinding.
En partant du principe, que le web service cible est implémenté en SOAP 1.2, la seule solution devient WSHttpBinding. Sauf que … WSHttpBinding impose soit une sécurité sur le transport (SSL) ou sur le message (certificat X.509). Il n’existe donc aucune solution dans WCF pour utiliser un service web basé sur HTTP Basic Auth sans protection (très mauvaise pratique, je l’accorde …).
La seule solution est donc un CustomBinding surchargeant BasicHttpBinding en lui imposant comme version de message SOAP 1.2.
public class MyBasicHttpBinding : BasicHttpBinding
    {
        public override BindingElementCollection CreateBindingElements()
        {
            Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
            Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
            BindingElementCollection bc = base.CreateBindingElements();
            bc.Remove(bc.Find<textmessageencodingbindingelement>());
            //Transport binding element must be the last
            bc.Insert(0, new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.Soap12 });
            return bc;
        }
    }

Pour le client :
var client = new MyWebserviceClient(new MyBasicHttpBinding(), new EndpointAddress("http://localhost:8090/MyWebservice"));
client.ClientCredentials.UserName.UserName = "my_user";
client.ClientCredentials.UserName.Password = "my_key";
client.doSomething();

mardi 5 avril 2011

Spring comme provider JPA au sein d’un conteneur EE5

Notamment dans JBoss 5, cela pose un problème. En effet, le conteneur va scanner l’ensemble des librairies pour trouver le ou les fichiers de définitions des “persistence units” (META-INF/persistence.xml). Or, lorsque l’on souhaite que ce soit Spring qui gère la création de l’”EntityManagerFactory”, ce fichier de définition peut être très succinct :
<persistence xmlns=&<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
    version="2.0">
 
 <persistence-unit name="myPersistenceUnit">
  <class>model.MyEntityClass</class>  
 </persistence-unit>
  
</persistence>
Cette description ne permettra pas au conteneur EE5 de démarrer cette “persistence unit” en l’absence de source de données.
Par exemple, sous JBoss 5 le serveur indiquera qu’une spécification n’est pas respectée :

Specification violation [EJB3 JPA 6.2.1.2] - You have not defined a non-jta-data-source for a RESOURCE_LOCAL enabled persistence context named: myPersistenceUnit

La solution consiste a renommer le fichier persistence.xml de telle sorte qu’il ne soit pas pris en compte par le serveur (exemple : jpa-persistence.xml).
Mais cela ne suffit pas : le conteneur va aussi scanner toutes les classes à la recherche de l’annotation  @PersistenceContext et sera incapable de charger la “persistence-unit” correspondante.
Là, l’attribut metadata-complete de l’élément web-app du fichier de configuration web.xml permet de préciser au conteneur de ne pas prendre en compte les annotations Java EE parce qu'elles sont gérées pas un autre mécanisme (Spring en l’occurrence dans notre cas).
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" metadata-complete="true">
</web-app>