web-dev-qa-db-fra.com

Comment puis-je passer un nom d'utilisateur/mot de passe dans l'en-tête à un SOAP Service WCF

J'essaie d'utiliser un service Web tiers https://staging.identitymanagement.lexisnexis.com/identity-proofing/services/identityProofingServiceWS/v2?wsdl

Je l'ai déjà ajouté en tant que référence de service, mais je ne sais pas comment passer les informations d'identification pour l'en-tête.

Comment puis-je faire en sorte que la demande d'en-tête corresponde à ce format?

<soapenv:Header>
    <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:UsernameToken wsu:Id="UsernameToken-49" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Username>12345/userID</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/ oasis-200401-wss-username-token-profile-1.0#PasswordText">password123</wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">d+VxCZX1cH/ieMkKEr/ofA==</wsse:Nonce>
            <wsu:Created>2012-08-04T20:25:04.038Z</wsu:Created>
        </wsse:UsernameToken>
    </wsse:Security>
</soapenv:Header>
20
vts

Il existe probablement une méthode plus intelligente, mais vous pouvez ajouter les en-têtes manuellement de la manière suivante:

var client = new IdentityProofingService.IdentityProofingWSClient();

using (new OperationContextScope(client.InnerChannel))
{
    OperationContext.Current.OutgoingMessageHeaders.Add(
        new SecurityHeader("UsernameToken-49", "12345/userID", "password123"));
    client.invokeIdentityService(new IdentityProofingRequest());
}

SecurityHeader est ici une classe personnalisée implémentée, qui nécessite quelques autres classes depuis que j'ai choisi d'utiliser des attributs pour configurer la sérialisation XML:

public class SecurityHeader : MessageHeader
{
    private readonly UsernameToken _usernameToken;

    public SecurityHeader(string id, string username, string password)
    {
        _usernameToken = new UsernameToken(id, username, password);
    }

    public override string Name
    {
        get { return "Security"; }
    }

    public override string Namespace
    {
        get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
    }

    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
        serializer.Serialize(writer, _usernameToken);
    }
}


[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
{
    public UsernameToken()
    {
    }

    public UsernameToken(string id, string username, string password)
    {
        Id = id;
        Username = username;
        Password = new Password() {Value = password};
    }

    [XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
    public string Id { get; set; }

    [XmlElement]
    public string Username { get; set; }

    [XmlElement]
    public Password Password { get; set; }
}

public class Password
{
    public Password()
    {
        Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
    }

    [XmlAttribute]
    public string Type { get; set; }

    [XmlText]
    public string Value { get; set; }
}

Je n'ai pas ajouté le bit Nonce au XML UsernameToken, mais il est très similaire à celui de Password. L'élément Created doit également être ajouté, mais il s'agit d'un simple [XmlElement].

33
Thorarin

Les réponses ci-dessus sont tellement fausses! NE PAS ajouter d’en-têtes personnalisés. À en juger par votre exemple XML, il s'agit d'un en-tête WS-Security standard. WCF le soutient définitivement. Lorsque vous ajoutez une référence de service, vous devez créer une liaison basicHttpBinding dans le fichier de configuration. Vous devrez le modifier pour inclure un élément de sécurité avec le mode TransportWithMessageCredential et un élément de message avec clientCredentialType = UserName:

<basicHttpBinding>
  <binding name="usernameHttps">
    <security mode="TransportWithMessageCredential">
      <message clientCredentialType="UserName"/>
    </security>
  </binding>
</basicHttpBinding>

La configuration ci-dessus indique à WCF d'attendre que l'ID utilisateur/mot de passe soit dans l'en-tête SOAP via HTTPS. Ensuite, vous pouvez définir votre identifiant/mot de passe dans votre code avant de passer un appel:

var service = new MyServiceClient();
service.ClientCredentials.UserName.UserName = "username";
service.ClientCredentials.UserName.Password = "password";

À moins que ce fournisseur de services ne s’écarte de la norme, cela devrait fonctionner.

57
Sergey

L'ajout d'un en-tête personnalisé codé en dur peut fonctionner (il peut également être parfois rejeté), mais c'est totalement une mauvaise façon de le faire. Le but de la WSSE est la sécurité. Microsoft a publié Microsoft Web Services Enhancements 2.0, puis WSE 3.0, pour cette raison. Vous devez installer ce package ( http://www.Microsoft.com/en-us/download/details.aspx?id=14089 ). 

La documentation n'est pas facile à comprendre, en particulier pour ceux qui n'ont pas travaillé avec SOAP et l'adressage WS. Tout d’abord, "BasicHttpBinding" est Soap 1.1 et il ne vous donnera pas le même en-tête de message que WSHttpBinding. Installez le paquet et regardez les exemples. Vous devrez référencer le DLL à partir de WSE 3.0 et vous devrez également configurer votre message correctement. Il existe un nombre énorme ou des variations dans l'en-tête WS Addressing. Celui que vous recherchez est la configuration de UsernameToken. 

Ceci est une explication plus longue et je devrais écrire quelque chose pour tout le monde car je ne peux pas trouver la bonne réponse nulle part. Au minimum, vous devez commencer par le package WSE 3.0.

2
Robin Briggs

J'ai une meilleure méthode d'ici: WCF: Créer des en-têtes personnalisés, comment ajouter et utiliser ces en-têtes

Le client s'identifie
Le but ici est de demander au client de fournir certaines informations que le serveur peut utiliser pour déterminer qui envoie le message. Le le code C # suivant ajoutera un en-tête nommé ClientId:

var cl = new ActiveDirectoryClient();

var eab = new EndpointAddressBuilder(cl.Endpoint.Address);

eab.Headers.Add( AddressHeader.CreateAddressHeader("ClientId",       // Header Name
                                                   string.Empty,     // Namespace
                                                    "OmegaClient")); // Header Value
cl.Endpoint.Address = eab.ToEndpointAddress();

// Now do an operation provided by the service.
cl.ProcessInfo("ABC");

Ce code ajoute un en-tête de noeud final nommé ClientId avec une valeur OmegaClient à insérer dans l'en-tête soap sans un espace de noms.

En-tête personnalisé dans le fichier de configuration du client
Il existe un autre moyen de faire un en-tête personnalisé. Cela peut être réalisé dans le fichier de configuration XML de le client où tous les messages ont été envoyés en spécifiant l'en-tête personnalisé comme une partie du point final de la manière suivante:

<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IActiveDirectory" />
            </basicHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://localhost:41863/ActiveDirectoryService.svc"
              binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IActiveDirectory"
              contract="ADService.IActiveDirectory" name="BasicHttpBinding_IActiveDirectory">
            <headers>
              <ClientId>Console_Client</ClientId>
            </headers>
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>
0
rebornx

Évidemment, cela fait des années que ce message est en vie - mais le fait est que je l’ai trouvé lorsque je recherchais un problème similaire. Dans notre cas, nous avons dû ajouter les informations de nom d'utilisateur/mot de passe à l'en-tête de sécurité. Cela diffère de l'ajout d'informations sur l'en-tête en dehors des en-têtes de sécurité. 

La bonne façon de procéder (pour les liaisons personnalisées/authenticationMode = "CertificateOverTransport") (comme sur le framework .Net version 4.6.1), consiste à ajouter les informations d'identification du client comme d'habitude:

    client.ClientCredentials.UserName.UserName = "[username]";
    client.ClientCredentials.UserName.Password = "[password]";

puis ajoutez un "jeton" dans l'élément de liaison de sécurité, car les informations d'identification nom d'utilisateur/mot de passe ne seraient pas incluses par défaut lorsque le mode d'authentification est défini sur certificat.

Vous pouvez définir ce jeton comme suit:

    //Get the current binding 
    System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding;
    //Get the binding elements 
    BindingElementCollection elements = binding.CreateBindingElements();
    //Locate the Security binding element
    SecurityBindingElement security = elements.Find<SecurityBindingElement>();

    //This should not be null - as we are using Certificate authentication anyway
    if (security != null)
    {
    UserNameSecurityTokenParameters uTokenParams = new UserNameSecurityTokenParameters();
    uTokenParams.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
security.EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams);
    }

   client.Endpoint.Binding = new CustomBinding(elements.ToArray());

Ça devrait le faire. Sans le code ci-dessus (pour ajouter explicitement le jeton de nom d'utilisateur), même la définition des informations de nom d'utilisateur dans les informations d'identification du client peut ne pas avoir pour résultat que ces informations d'identification soient transmises au service.

0
Phantom2018

Supposons que vous appeliez un service Web utilisant HttpWebRequest et HttpWebResponse, car le client .Net supporte la structure du WSLD que vous essayez de consommer.

Dans ce cas, vous pouvez ajouter les informations d'identification de sécurité sur les en-têtes, telles que:

<soap:Envelpe>
<soap:Header>
    <wsse:Security soap:mustUnderstand='true' xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'><wsse:UsernameToken wsu:Id='UsernameToken-3DAJDJSKJDHFJASDKJFKJ234JL2K3H2K3J42'><wsse:Username>YOU_USERNAME/wsse:Username><wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>YOU_PASSWORD</wsse:Password><wsse:Nonce EncodingType='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'>3WSOKcKKm0jdi3943ts1AQ==</wsse:Nonce><wsu:Created>2015-01-12T16:46:58.386Z</wsu:Created></wsse:UsernameToken></wsse:Security>
</soapHeather>
<soap:Body>
</soap:Body>


</soap:Envelope>

Vous pouvez utiliser SOAPUI pour obtenir la sécurité wsse à l’aide du journal http.

Faites attention car ce n'est pas un scénario sûr.

0
Matvi

Supposons que vous ayez la référence de service du nom localhost dans votre web.config afin que vous puissiez aller comme suit

localhost.Service objWebService = newlocalhost.Service();
localhost.AuthSoapHd objAuthSoapHeader = newlocalhost.AuthSoapHd();
string strUsrName =ConfigurationManager.AppSettings["UserName"];
string strPassword =ConfigurationManager.AppSettings["Password"];

objAuthSoapHeader.strUserName = strUsrName;
objAuthSoapHeader.strPassword = strPassword;

objWebService.AuthSoapHdValue =objAuthSoapHeader;
string str = objWebService.HelloWorld();

Response.Write(str);
0
शेखर