正确的方式与SOAP webservice沟通WSSE Usernametoken

我试图通过相应的wsdl来使用Web服务。 此服务依赖于符合Web服务安全基本安全configuration文件1.0的身份validation,包括http://docs.oasis-open.org/wss/2004/01/oasis-200401wss-wssecurity-secext-1.0的正确xml名称空间。 xsd必须包含在请求中。

例:

<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> 

我的第一次尝试是沿着Add Service Reference目标wsdl和生成的代理使用它们的行

 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); } 

然而,试图用Fiddler询问SOAP消息,我发现没有添加UsernameToken元素。

什么是履行这个合同的正确方法?

编辑:以下来自@John桑德斯响应我试图改变我的代码使用wsHttpBinding

 var wsHttpBinding = new WSHttpBinding(SecurityMode.Transport); wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; 

使用此绑定SOAP消息变成

 <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> 

这添加了Header元素,而不是使用BasicHttpBinding引用原始soap消息的wsse:UsernameToken元素

 <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> 

如果我改变绑定

 var wsHttpBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential); wsHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName; 

我得到的SOAP消息是

 <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> 

这似乎是非常接近的,但是这似乎实际上encryption了肥皂消息的正文,这是我不想发生的事情。

如果我指定wsHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName; 只使用SecurityMode.Transport它回到它说匿名的地方。

最后的障碍是什么,我不能清楚这一点?

最终的解决scheme:我想提出这个incase它帮助某人,这里没有什么不同,其他的UserToken对象被包装在一个安全节点,这是我的服务提供者所需要的,似乎是从我之前的例子的输出我可以生成。

 <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> 

请参阅使用C#,使用WSSE纯文本身份validation的WCF SOAP使用者? 如何使用代码进行configuration,而不是configuration

如果您需要通过HTTPS发送UserName,则可以使用标准方法(如果您的WSDL已正确定义,则应通过添加服务引用自动为您创build):

 <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> 

你可以在代码中定义绑定:

 var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential); basicHttpBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; 

现在您将在代理中设置凭据:

 client.ClientCredentials.UserName.UserName = "bob"; client.ClientCredentials.UserName.Password = "1234"; 

如果您只需要HTTP上的UserNameTokenconfiguration文件而无需其他任何WS-Security基础架构,则最简单的方法就是使用ClearUserNameBinding 。

如果您需要来自客户端的所有请求需要相同的用户名和密码,则可以使用简单的basicHttpBinding,而不具有任何安全性,并包含来自configuration的静态头:

 <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> 

如果你需要更复杂的东西来显示WSDL(安全断言)的相关部分或示例SOAP请求。 另外提及您是否需要使用HTTP或HTTPS。

@拉迪斯拉夫答案是正确的。 但是,我正在尝试使用SOAP 1.1 Web服务获取MessageSecurityException 。 在Scott Hanselman的这篇博客文章之后,我能够做到这一点。 这是我最终使用的代码:

  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); 

使用wsHttpBinding,而不是basicHttpBinding。

实际上,您应该只使用“添加服务引用”并指向服务的WSDL。