WCF client passing username token with mustUnderstand set to true

半世苍凉 提交于 2021-02-18 22:24:27

问题


I'm tasked with creating a WCF service that will be consumed by an external client. The client is using WSSE security, specifically, they're passing a username token via a SOAP header.

The WCF service is hosted on an IIS server with SSL enabled.

At this point, I have a semi-working prototype. The issue I'm dealing with now is that the SOAP header has the mustUnderstand attribute set to 1, and this causes the process to fail.

I'd like some advice (or better yet, a code example smiles) on how to handle the username token in such a fashion as to return the proper response when the mustUnderstand attribute is true.

Here's a sample of the SOAP request that's failing:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
       <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>
                <wsse:Username>TestUser</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">TestPWD</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">NzU3MjFhN2YtYTlmYS00ZWZjLTkxNjktY2ExZjlkZDEwNzE5</wsse:Nonce>
                <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2011-10-26T03:04:39Z</wsu:Created>
             </wsse:UsernameToken>
          </wsse:Security>
       </soapenv:Header>
       <soapenv:Body>
          <tem:Getstuff>
             <tem:Arg1>Arg1</tem:Arg1>
             <tem:Arg2>Arg2</tem:Arg2>
          </tem:Getstuff>
       </soapenv:Body>
    </soapenv:Envelope>

If soapenv:mustUnderstand="1" is changed to soapenv:mustUnderstand="0", then the process works.


PS: Here's a revised sample request the client sent:

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <s:Header>
        <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/WService/Getstuff</Action>
        <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="removed" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:Username>TestUser</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">TestPass</wsse:Password>
            <wsse:Nonce>2Udx78sh2y2xRJYJpZZ9+w==</wsse:Nonce>
            <wsu:Created>2011-09-26T19:12:48Z</wsu:Created>
          </wsse:UsernameToken>
        </Security>
      </s:Header>
      <s:Body>
        <Getstuff xmlns="http://tempuri.org/">
         <Arg1>Arg1</Arg1>
         <Arg2>Arg2</Arg2>
        </Getstuff>
      </s:Body>
    </s:Envelope>

I receive the following response to the above requests:

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
       <s:Body>
          <s:Fault>
             <faultcode>s:MustUnderstand</faultcode>
             <faultstring xml:lang="en-US">The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed.  This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process.  Please ensure that the configuration of the client's binding is consistent with the service's binding.</faultstring>
          </s:Fault>
       </s:Body>
    </s:Envelope>

Here's the binding:

<bindings>
  <basicHttpBinding>
    <binding name="TransportBind" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
      maxReceivedMessageSize="2147483647">
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
        maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
      <security mode="Transport">
        <transport clientCredentialType="None" />
      </security>
    </binding>
    <binding name="basic" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
      maxReceivedMessageSize="2147483647">
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
        maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
    </binding>
  </basicHttpBinding>
</bindings>

回答1:


Your binding is basicHttpBinding. You need to use wsHttpBinding.




回答2:


I solved this issue by not using the generated WS-Security header (when you add the Service Reference) in the WCF configuration, but rather commenting this out and instead letting .NET generate the header itself by using Client Credentials and specifying a Security Mode of "TransportWithMessageCredential":

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

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

(We are using SSL, so hence this security setting).

Commented-out generated header:

 <client>
        <endpoint ...>
            <!--<headers>
                <wsse:Security...>
                </wsse:Security>
            </headers>-->
        </endpoint>
 </client>

Unfortunately I don't know enough WCF to capture the raw soap request/response to compare the difference and see why ClientCredentials doesn't cause the "was not understood" fault, while the generated header does.

As an aside, according to the MSDN documentation, if you only use "Transport" it won't know to use WS-Security: "Leave this property at its default value, which is System.ServiceModel.SecurityMode.Transport to not use WS-Security."




回答3:


+1 @JohnSaunders because he is most likely barking up the right tree here.

Is your client .NET/WCF? If not, it may not be implementing WS-Security, or at least not in the way WCF wants it to.

If the client is .NET, this is just an mismatched binding on the client side.

The mustUnderstand flag says that the WS-Security header must be acknowledged and processed. A non-WS-Security client, whether it's because it doesn't speak WS-Security or isn't configured to, will ignore the header, try to use the message anyway and the server will punt.

Your other option is to turn of repudiation on the server. It'll stop sending WS-Security headers. Of course, then you don't get repudiation.



来源:https://stackoverflow.com/questions/8038003/wcf-client-passing-username-token-with-mustunderstand-set-to-true

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!