C#消费soap WS在VerifyIncomingMessage中返回安全头错误

Posted

技术标签:

【中文标题】C#消费soap WS在VerifyIncomingMessage中返回安全头错误【英文标题】:C# consuming soap WS returns Security header error in VerifyIncomingMessage 【发布时间】:2020-09-24 20:56:11 【问题描述】:

我有一个 SoapUI 项目,它的请求带有这样的soap标头中的凭据

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:rgw="http://ThirdPartyWebService.wsdl">
 <soapenv:Header>
  <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <wsse:UsernameToken wsu:Id="UsernameToken-12346579123456789">
  <wsse:Username>username</wsse:Username>
  <wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
.........
  </soapenv:Body>
</soapenv:Envelope>

SoapUI 项目运行良好,我得到了这样的回应:

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <env:Header/>
   <env:Body>
      <m:ThirdPartyWSMethodResponse xmlns:m="http://gr/gsis/ThirdPartyWS/ThirdPartyWS.wsdl">
         <ThirdPartyWSBasic_out>
            <m:string1>string 1</m:string1>
            <m:date1 xsi:nil="true"/>
            <m:string2>string 2</m:string2>
         </ThirdPartyWSBasic_out>
         <arrayOfThirdPartyWSFirmAct_out>
            <m:ThirdPartyWSFirmActUser>
               <m:Descr>some free text</m:Descr>
               <m:Kind>1</m:Kind>
               <m:KindDescr>some string</m:KindDescr>
               <m:Code>some code as string</m:Code>
            </m:ThirdPartyWSFirmActUser>
         </arrayOfThirdPartyWSFirmAct_out>
         <pCallSeqId_out>111111111</pCallSeqId_out>
         <pErrorRec_out>
            <m:errorDescr xsi:nil="true"/>
            <m:errorCode xsi:nil="true"/>
         </pErrorRec_out>
      </m:ThirdPartyWSMethodResponse>
   </env:Body>
</env:Envelope>

我正在尝试使用此代码在 C# 项目中使用相同的肥皂 WS(我将其添加为服务参考):

    ThirdPartyWSClient client = new ThirdPartyWSClient();
    client.ClientCredentials.UserName.UserName = "username";
    client.ClientCredentials.UserName.Password = "password";

    System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) =>  return true; ;
    ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

    ThirdPartyWSInputUser inputBody = new ThirdPartyWSInputUser();
    inputBody.parameter1 = "800542811";

    ThirdPartyWSBasicUser ThirdPartyWSBasic_out = new ThirdPartyWSBasicUser();
    ThirdPartyWSUserArray arrayOfThirdPartyWS_out = new ThirdPartyWSUserArray();
    decimal pCallSeqId_out = new decimal();
    GenWsErrorUser pErrorRec_out = new GenWsErrorUser();
    client.thirdPartyWSMethod(inputBody, ref ThirdPartyWSBasic_out, ref arrayOfThirdPartyWS_out, ref pCallSeqId_out, ref pErrorRec_out);

带绑定:

        <bindings>
            <basicHttpBinding>
                <binding name="ThirdPartyWSPublic">
                    <security mode="TransportWithMessageCredential" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://www.ThirdPartyWS/ThirdPartyWSPublicPort"
                binding="basicHttpBinding" bindingConfiguration="RgWsPublic"
                contract="SoapWebService.ThirdPartyWSPublic" name="ThirdPartyWSPublicPort" />
        </client>

我收到以下错误:

安全处理器无法在邮件中找到安全标头。这可能是因为消息是不安全的错误,或者是因为通信双方之间存在绑定不匹配。如果服务配置了安全性并且客户端未使用安全性,则可能会发生这种情况。 使用此堆栈跟踪:


Server stack trace: 
   at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessageCore(Message& message, TimeSpan timeout)
   at System.ServiceModel.Security.TransportSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout)
   at System.ServiceModel.Security.SecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at .................................

问题是无法验证传入的消息。我使用了 fiddler,发现 我得到了来自 WS 的正确响应!唯一看起来很奇怪的是,我的请求在标头中包含了一个时间戳元素,它没有 wsse: 和 soapenv: 预期的标签,但是是这样的:

<s:Envelope
    xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <o:Security s:mustUnderstand="1"
            xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2020-06-05T13:35:58.208Z</u:Created>
                <u:Expires>2020-06-05T13:40:58.208Z</u:Expires>
            </u:Timestamp>
            <o:UsernameToken u:Id="uuid-11111111111111111111">
                <o:Username>username</o:Username>
                <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</o:Password>
            </o:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body>
        <ThirdPartyWSPublicMethod>
        ...
        </ThirdPartyWSPublicMethod>
    </s:Body>
</s:Envelope>

Web 服务是公共部门的 WS,需要身份验证,因此我无法提供。不幸的是,我无法显示确切的请求和响应,因为它们包含敏感的个人数据。 我已经尝试了我在这里和那里找到的所有东西,但无法解决这个问题。任何帮助将不胜感激!谢谢

【问题讨论】:

我认为超时是代码正在等待您不需要的代理。尝试禁用代理:***.com/questions/6579756/… 【参考方案1】:

我设法通过使用自定义绑定和禁用时间戳和代理解决了这个问题。感谢@jdweng 指出正确的方向

   <customBinding>
    <binding name="ThirdPartyWSPublic">
      <security authenticationMode="UserNameOverTransport" includeTimestamp="false">
        <secureConversationBootstrap />
      </security>
      <textMessageEncoding messageVersion="Soap11" />
      <httpsTransport useDefaultWebProxy="false" requireClientCertificate="false" />
    </binding>
  </customBinding>

【讨论】:

以上是关于C#消费soap WS在VerifyIncomingMessage中返回安全头错误的主要内容,如果未能解决你的问题,请参考以下文章

在 .net Core 中调用 SOAP 服务

在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?

从头开始使用 WS-Addressing 和 WS-Security 创建 SOAP 标头

gsoap - SOAP Header 中的 WS-Addressing 元素

JAX-WS - 添加 SOAP 标头

如何使用 Java JAX-WS 添加 SOAP 标头