c# - través - Forma correcta de comunicar el nombre de usuario de WSSE enviado al servicio web de SOAP
wsse security sunat (3)
@Ladislav respuesta es correcta. Sin embargo, recibía MessageSecurityException
para un servicio web SOAP 1.1 que intentaba usar. Después de esta publicación del blog de Scott Hanselman, pude hacerlo funcionar. Este es el código que uso:
var oldBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
oldBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
//remove the timestamp
BindingElementCollection elements = oldBinding.CreateBindingElements();
elements.Find<SecurityBindingElement>().IncludeTimestamp = false;
//sets the content type to application/soap+xml
elements.Find<TextMessageEncodingBindingElement>().MessageVersion = MessageVersion.Soap11;
CustomBinding newBinding = new CustomBinding(elements);
Estoy intentando consumir un servicio web a través de su wsdl correspondiente. Este servicio depende de que la autenticación se ajuste a los Servicios web Security Basic Security Profile 1.0, incluido el espacio de nombres xmls correcto de http://docs.oasis-open.org/wss/2004/01/oasis-200401wss-wssecurity-secext-1.0.xsd debe incluirse en la solicitud.
Ejemplo:
<wsse:UsernameToken xmlns:wsse=''http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'' >
<wsse:Username>
Bob
</wsse:Username>
<wsse:Password Type=''http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText''>
1234
</wsse:Password>
</wsse:UsernameToken>
Mis primeros intentos fueron a lo largo de las líneas Add Service Reference
apuntan al wsdl y a los proxies generados utilizándolos como tales
ServicePointManager.ServerCertificateValidationCallback =
(object s, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors) => true;
var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
var endpoint = new EndpointAddress("https://secure-ausomxana.crmondemand.com/..."
using (var client = new ContactClient(basicHttpBinding, endpoint))
{
var credential = client.ClientCredentials.UserName;
credential.UserName = "bob";
credential.Password = "1234";
var input = ...
var output = client.ContactQueryPage(input);
}
Sin embargo, al intentar interrogar los mensajes SOAP con Fiddler, veo que no se ha agregado ningún elemento UsernameToken.
¿Cuál es la forma correcta de cumplir este contrato?
Editar: siguiendo la respuesta de @John Saunders intenté alterar mi código para usar un wsHttpBinding
var wsHttpBinding = new WSHttpBinding(SecurityMode.Transport);
wsHttpBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
Usando este enlace el mensaje SOAP se convierte
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">document/urn:crmondemand/ws/ecbs/contact/10/2004:ContactQueryPage</a:Action>
<a:MessageID>urn:uuid:17807f44-1fcasfdsfd</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://secure-ausomxana.crmondemand.com/Services/Integration</a:To>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ContactQueryPage_Input xmlns="urn:crmondemand/ws/ecbs/contact/10/2004">
<ListOfContact xmlns="urn:/crmondemand/xml/Contact/Query">
<Contact>
<Id>1-asdfd</Id>
</Contact>
</ListOfContact>
</ContactQueryPage_Input>
</s:Body>
</s:Envelope>
Esto agrega el elemento Encabezado, a diferencia del elemento wsse:UsernameToken
para referencia, el mensaje original que usa BasicHttpBinding es
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ContactQueryPage_Input xmlns="urn:crmondemand/ws/ecbs/contact/10/2004">
<ListOfContact xmlns="urn:/crmondemand/xml/Contact/Query">
<Contact>
<Id>1-asdfds</Id>
</Contact>
</ListOfContact>
</ContactQueryPage_Input>
</s:Body>
</s:Envelope>
Si cambio el enlace para ser
var wsHttpBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
El mensaje SOAP que saco es
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</a:Action>
<a:MessageID>urn:uuid:eeb75457-f29e-4c65-b4bf-b580da26e0c5</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://secure-ausomxana.crmondemand.com/Services/Integration</a:To>
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="_0">
<u:Created>2011-05-02T13:30:09.360Z</u:Created>
<u:Expires>2011-05-02T13:35:09.360Z</u:Expires>
</u:Timestamp>
<o:UsernameToken u:Id="uuid-dc3605a0-6878-42f4-b1f2-37d5c04ed7b4-2">
<o:Username>Bob</o:Username>
<o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">1234</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body>
<t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:Entropy>
<t:BinarySecret u:Id="uuid-7195ad74-580b-4e52-9e2c-682e5a684345-1" Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce">bI4xuyKwZ8OkQYBRnz2LDNV+zhIOnl0nwP24yI1QAwA=</t:BinarySecret>
</t:Entropy>
<t:KeySize>256</t:KeySize>
</t:RequestSecurityToken>
</s:Body>
</s:Envelope>
Esto parece estar muy cerca, pero parece que en realidad ha encriptado el cuerpo del mensaje de jabón, algo que NO quiero que suceda.
Si especifico wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
con solo usar SecurityMode.Transport
regresa a donde dice que es anónimo.
¿Cuál es el obstáculo final que no puedo aclarar sobre esto?
Solución final: Imaginé que publicaría esto en caso de que ayude a alguien, no hay mucha diferencia aquí, el objeto UserToken está envuelto en un nodo de seguridad, que es lo que mi proveedor de servicios requirió y parece ser el resultado de mis ejemplos anteriores de lo que Podría ser generado.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Contact" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="524288" maxBufferPoolSize="524288" maxReceivedMessageSize="524288"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="65536" maxArrayLength="131072"
maxBytesPerRead="32768" maxNameTableCharCount="131072" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://secure-ausomxana.crmondemand.com/Services/Integration"
binding="basicHttpBinding" bindingConfiguration="Contact"
contract="OnDemandContactService.Contact" name="OnDemand.Contact.Endpoint">
<headers>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>USERNAME</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">PASSWORD</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</headers>
</endpoint>
</client>
</system.serviceModel>
Consulte con C #, WCF SOAP consumidor que usa autenticación de texto plano WSSE? para saber cómo configurarlo usando código y no config
Si necesita enviar nombre de usuario a través de HTTPS, puede usar el enfoque estándar (si su WSDL está definido correctamente, debe crearlo automáticamente agregando referencia de servicio):
<bindings>
<basicHttpBinding>
<binding name="secured">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="..." address="https://..." contract="..." binding="basicHttpBinding"
bindingConfiguration="secured" />
</client>
Ar puede definir el enlace en el código:
var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
Establecerá las credenciales en el proxy como lo hace ahora:
client.ClientCredentials.UserName.UserName = "bob";
client.ClientCredentials.UserName.Password = "1234";
Si solo necesita el perfil UserNameToken a través de HTTP sin ninguna otra infraestructura de WS-Security, el enfoque más simple es usar ClearUserNameBinding .
Si necesita el mismo nombre de usuario y contraseña para todas las solicitudes del cliente, puede usar basicHttpBinding simple sin ninguna seguridad e incluir el encabezado estático de la configuración:
<client>
<endpoint ...>
<headers>
<wsse:UsernameToken xmlns:wsse=''http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'' >
<wsse:Username>Bob</wsse:Username>
<wsse:Password Type=''http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText''>
1234
</wsse:Password>
</wsse:UsernameToken>
</headers>
</endpoint>
</client>
Si necesita algo más complejo, muestre la parte relevante de WSDL (aserción de seguridad) o muestree la solicitud SOAP. También mencione si debe usar HTTP o HTTPS.
Use wsHttpBinding, no basicHttpBinding.
De hecho, debería usar "Agregar referencia de servicio" y señalar el WSDL del servicio.