[C#]Ajouter un header SOAP dans un client de service web

Hello les geeks

J’essaie de faire un petit client pour service web en C#. Le service web a été codé en Java et tourne sur un serveur Glassfish.

J’ai récupéré sans trop de problème de .wsdl du service web, et Visual Studio m’a bien gentiment créé une classe client me permettant d’appeler les méthodes du service web.

Seulement voilà, certaines méthodes du service sont “sécurisées” : je dois taper un login/pass dans le header soap de la “requête” pour que le service daigne répondre. Or je ne trouve aucune méthode dans la classe créée par VS pour modifier ce header avant d’appeler la méthode “sécurisée”.

En lisant de la doc j’ai créé une classe dérivée de SoapHeader, mais je ne vois pas trop comment l’insérer efficacement.

Un peu de code:

static void Main(string[] args)
{
    SBankingClient proxy = new SBankingClient(); //classe crée par VS sur base du .wsdl du web service
    Console.WriteLine("Récupération des mouvements du jour...");
    String listing = proxy.getDayMoves(); //méthode lambda du web service
    if (listing == null)
        Console.WriteLine("Pas de mouvements aujourd'hui");
    else
        Console.WriteLine("Mouvements du jour : \n" + listing);
    Console.WriteLine("Vérification de votre compte...");
    float montant = proxy.getState("xxx"); //test avec xxx qui est un compte existant
    Console.WriteLine("Vous avez {0} brouzoufs", montant);
    Console.ReadKey();
}

Code qui fonctionne sans ces énervants headers soap.

Ce que j’ai vainement tenté de rajouter (et là le web service m’envoie chier parce que le header soap est vide d’après lui) :

proxy.ClientCredentials.UserName.UserName = "xxx";
proxy.ClientCredentials.UserName.Password = "yyy";

Ce qui doit sûrement se passer:

public class AuthHeader : SoapHeader
{
    public string login;
    public string pass;
}
static void Main(string[] args)
{
    SBankingClient proxy = new SBankingClient(); //classe crée par VS sur base du .wsdl du web service
    AuthHeader auth = new AuthHeader();
    auth.login = "xxx";
    auth.pass = "yyy";
    /*
    * Stuff to do here
    * ???
    * PROFIT !
    */
}

Et là j’implore votre aide pour remplir ce %µ£*!§ d’header soap.

Je me souviens d’avoir fait ce cas dans une de mes anciennes boites, et je me demande si c’est pas carrement au niveau de la connection qu’il faut gerer l’auth, avant meme de passer par le webservice. Jettes un oeil de ce coté la. Ca ressemble a tellement de cas que j’ai resolu que je saurais meme pas si faut pas feinter avec autre chose en plus. Le client credential, ca me semble la bonne voie, mais je vois pas pourquoi ca passe pas du coté du webservice. Tu sais quel type d’auth c’est ? avec certificat ? etc. Ca pourrait aider a t’orienter. (Avec un certificat c’est plus bas qu’il faudrat specifier l’auth).

Hello,
Tu es tombé sur cet exemple là dans tes recherches ? Ca ressemble à ce que tu veux faire.

Faire ça à la main, c’est pas gagné …
Tu utilises quelle version de DotNet ?

Si c’est la 2, as-tu installé WSE 3 ?

Enfin, est-ce que le Web Service utilise un certificat ou uniquement une authentification ?

Il te faut rajouter une propriété sur ton proxy client (du style “Auth”) de ton type héritant de SoapHeader, et la décorer avec l’attribut SoapHeaderAttribute.

Par contre tu vas certainement devoir écrire le proxy à la main (affiche les fichiers cachés et recopie le contenu de Reference.cs dans ton projet).

Exemple ici (Le lien de DrDrakeRamore renvoie sur le même exemple) : http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapheaderattribute.aspx

PS : Sinon WSE3 ne semble pas être utile pour ton cas, vu qu’à priori il s’agit d’une auth custom via une entête custom elle aussi.

PS2 : Dans mon cas, j’ai fini par écrire une SoapExtension qui est inclue dans tous mes appels (déclaration via fichier de config) et qui bosse directement sur l’xml après sérialisation, cela m’économise de rajouter les propriétés & attributs sur toutes mes méthodes. Mais cela n’est utile que si tu va avoir beaucoup de proxy clients à utiliser et que tu veux éviter d’avoir à ajouter cet attribut à chaque fois.

Comment vois-tu qu’il s’agit d’une authentification custom ?

Il faudrait effectivement savoir comment est implémentée la sécurité dans le Web Service. S’il s’agit -généralement oui- d’une implémentation de WSS, tous les outils sont disponibles dans Visual Studio (au pire 1 téléchargement chez Microsoft) pour configurer automatiquement le client généré sans créer soi-même de classe héritant de SoapHeader …

Si le client est en WCF, il peut arriver que la configuration ne retrouve pas directement la bonne solution, il faut modifier le binding mais là non plus, pas de code supplémentaire à ajouter au proxy.

Côté web service, il a été implémenté via Metro pour Glassfish (qui est sensé être compatible avec .net 3.0).

Le souci du header, c’est qu’il est vérifié par un objet de type MessageHandler. J’ai essayé de créer un petit web service de la même façon pour tester, et j’ai des soucis pour le configurer. Soit j’utilise également un MessageHandler (qui va regarder si le header soap contient des infos de login), soit il y a moyen de “Set Web Service Attributes” sous Netbeans, j’arrive alors dans un menu de la sorte:

http://docs.sun.com/source/821-0015/images/ep-http-bc-wspolicy.gif

J’ai l’impression que “Username Authentication with symmetric key” est ce qui se rapproche le plus d’un unsernametoken, mais c’est pas encore ça :ermm: