web-dev-qa-db-fra.com

Ajout de SOAP en-têtes implicites à WSDL

Ma question est similaire à celle-ci. Comment passer l'en-tête Soap lorsque WSDL ne le définit pas? Mais c'est différent.

Pour un service Web que j'utilise, toutes les méthodes nécessitent une authentification qui est envoyée en texte clair dans un en-tête SOAP). Cependant, mon WSDL n'inclut aucune information d'en-tête soap. J'ai un outil de plateforme personnalisé qui Je dois utiliser pour générer du code à partir du WSDL. Étant donné que les informations d'en-tête ne sont pas disponibles, je ne peux pas utiliser directement la classe générée - je ne souhaite pas modifier manuellement le code pour l'adapter à l'en-tête.

J'ai essayé de spécifier l'en-tête SOAP dans le WSDL mais je n'ai pas réussi à obtenir les espaces de noms corrects. Le WSDL est ici https://stage.totalcheck.sensis.com.au/service/webservice? wsdl et l'en-tête SOAP) est comme suit:

    <soapenv:Header>
        <wsse:Security>
            <wsse:UsernameToken>
                <wsse:Username>username</wsse:Username>
                <wsse:Password>password</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
   </soapenv:Header>

Est-ce que quelqu'un peut m'aider? Merci!

16
Vid L

D'un point de vue conceptuel, WSDL n'est pas censé définir des en-têtes. WSDL sert uniquement à définir les aspects fonctionnels d'un service, tels que les opérations, les messages, la liaison et les points de terminaison. Les messages et les liaisons définissent comment la charge utile des messages doit être codée et formatée.

Les en-têtes de SOAP messages cependant n'appartiennent pas à la charge utile. Ils sont généralement utilisés pour configurer les propriétés non fonctionnelles d'un SOAP processeur. La sécurité est un tel propriété non fonctionnelle. L'aspect fonctionnel de la charge utile n'est pas affecté. Il est seulement assuré que la communication est sécurisée et la pile d'outils WS, et non l'implémentation du service, doit s'en occuper.

Ainsi, la pièce manquante est désormais une norme qui permet d'attacher certaines exigences non fonctionnelles aux services WSDL, afin que les générateurs de code puissent automatiquement dériver les en-têtes à envoyer et/ou comprendre afin de remplir la propriété non fonctionnelle comme souhaité - - sans avoir à traiter manuellement les champs d'en-tête. Ce standard existe et s'appelle WS-Policy . Une politique contient généralement un ensemble d'alternatives qui exposent un ensemble d'exigences que le fournisseur et le consommateur devraient être en mesure de remplir. Lorsque deux services sont censés interagir l'un avec l'autre, les deux politiques sont prises et une soi-disant "politique efficace" est calculée. Il définit les exigences non fonctionnelles communes. À l'aide de ces informations, le fournisseur et le consommateur peuvent se configurer pour ajouter les en-têtes requis, comme les en-têtes WS-Security. WS-SecurityPolicy définit également un ensemble de stratégies pouvant être utilisées. WS-PolicyAttachment définit comment ces politiques peuvent être attachées à un WSDL.

Il existe des générateurs de code qui peuvent gérer les politiques WS, par exemple Metro ou Axis2

20
vanto

Vous pouvez ajouter des informations d'en-tête soap aux appels de méthode en décorant les méthodes de la classe proxy générée à partir du wsdl avec l'attribut SoapHeader.

Par exemple, wsdl.exe générera la classe de proxy client Reference.cs pour la référence de service Web lorsque vous "Ajouter une référence Web". Dans le lien mentionné ci-dessus https://stage.totalcheck.sensis.com.au/service/webservice?wsdl il y a un message suggestAddress qui se traduira par une méthode dans le proxy client reference.cs généré code fichier lorsque vous ajoutez une référence Web à partir de Visual Studio. Par défaut, lorsque cette méthode est appelée, il n'y aura pas d'en-tête dans l'enveloppe de savon. Pour ajouter un SoapHeader à l'enveloppe pour cette demande, ajoutez un attribut [SoapHeader ("Security")] en haut de la méthode SuggérerAddress dans la classe générée Reference.cs, où "Security" est une classe qui hérite de la classe de base SoapHeader.

Exemple pour le Security SoapHeader requis ci-dessus, vous devez créer les classes suivantes,

public partial class Security : SoapHeader
{
    public UserNameToken UserNameToken { get; set; }
}

public partial class UserNameToken
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

Ensuite, vous décoreriez la méthode SuggestionAddress dans reference.cs comme suit,

[SoapHeader("Security")]
public suggestAddressesResult suggestAddresses([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] addressSearch search) {
        object[] results = this.Invoke("suggestAddresses", new object[] {search});
        return ((suggestAddressesResult)(results[0]));
    }

Cela garantira que chaque enveloppe créée lorsque la méthode suggestAddress est appelée contient un en-tête de sécurité qui ressemble à celui mentionné ci-dessus,

<soapenv:Header>
    <wsse:Security>
        <wsse:UsernameToken>
            <wsse:Username>username</wsse:Username>
            <wsse:Password>password</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>
4
Roger

La clé pour moi en utilisant cette question pour m'aider était de reconnaître (comme certains l'ont souligné) que les en-têtes en question sont ceux de la norme WS-Security.

Si votre outil de génération de proxy est "personnalisé", il semble logique que vous ayez un commutateur pour ajouter automatiquement les en-têtes pour WS-Security. Toutefois, si vous utilisez WSDL.exe ("Ajouter une référence Web" dans Visual Studio), considérez svcutil.exe à la place ("Ajouter une référence de service").

Si vous utilisez un proxy WCF, vous pouvez remplacer la configuration donnée et autoriser WCF à ajouter les en-têtes pour vous:

<security mode="TransportWithMessageCredential">
    <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

De là, vous pouvez spécifier le mot de passe:

RemoteSvcProxy.TheirClient client = new RemoteSvcProxy.TheirClient();
client.ClientCredentials.UserName.UserName = "uname";
client.ClientCredentials.UserName.Password = "pwd";

Je ne sais pas quel est votre outil personnalisé, mais peut-être que le cadre sur lequel il est basé a également des options de configuration similaires.

1
b_levitt