Question

i'm not a WCF expert, and i know just the basics of service security, so maybe most of the things that i'll point out will be wrong. That said, i need to invoke a 3d party service that requires a specific format for the SOAP header. They require that the soap header provides: 1) timestamp block 2) Binary Token 3) digest (checksum of a part of data to encrypt)

They've provided me this exemple of request (i've removed the sensible parts)

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Header>
    <wsse:Security 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:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"
                                wsu:Id="...omissis...">
      </wsse:BinarySecurityToken>

      <ds:Signature Id="SIG-6" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
            <ec:InclusiveNamespaces PrefixList="S" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          </ds:CanonicalizationMethod>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#TS-5">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                <ec:InclusiveNamespaces PrefixList="wsse S" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
              </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>...omissis...</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
          ....
          ...omissis...
          ....
        </ds:SignatureValue>
        <ds:KeyInfo Id="KI-...omissis...">
          <wsse:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1" wsu:Id="STR-...omissis..." xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
            <wsse:Reference URI="#X509-...omissis..." ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"/>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
      <wsu:Timestamp wsu:Id="TS-5">
        <wsu:Created>2013-03-27T15:10:18.523Z</wsu:Created>
        <wsu:Expires>2013-03-27T15:26:58.523Z</wsu:Expires>
      </wsu:Timestamp>
    </wsse:Security>
  </S:Header>
<S:Body>
    ...clear (not encrypted) body of the soap request
</S:Body>
</S:Envelope>

They gave me also a WSDL and an xsd. What i've done was to create a new web application, using the wsdl as service reference. Checking the web.config, i can see that this have created a basicHttpBinding like this

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="CPBinding">
          <security mode="Transport" />
        </binding>
        <binding name="CPBinding1" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://...omissis"
        binding="basicHttpBinding" bindingConfiguration="CPBinding"
        contract="BTClient.CPCUVPortType" name="CPCUVPort" />
    </client>
  </system.serviceModel>

But this binding doesn't use any kind of security policy, so i've created a behaviour that takes into account the certificates (for a mutual certificate) like that

 <behaviors>
      <endpointBehaviors>
        <behavior name="CustomBehaviorForCertificates">
          <clientCredentials>
            <clientCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="...omissis..." />
            <serviceCertificate>
              <scopedCertificates>
                <add targetUri="https://...omissis..." storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindByThumbprint" findValue="...omissis..." />
              </scopedCertificates>
              <authentication certificateValidationMode="PeerTrust" revocationMode="NoCheck" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>

And referenced this on the binding. By inspecting the outgoing messages (using the method BeforeSendRequest of a custom Inspector) i can see that it totally ignores the certificates, sending the same request as the without-behaviour one. The 3d party service answer to my request like this:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsu:Timestamp wsu:Id="Timestamp-..." xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsu:Created>2013-09-06T14:31:28Z</wsu:Created>
        <wsu:Expires>2013-09-06T14:36:28Z</wsu:Expires>
      </wsu:Timestamp>
      <wsse:BinarySecurityToken wsu:Id="SecurityToken-...." EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        ...omissis...
      </wsse:BinarySecurityToken>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
          <Reference URI="#Timestamp-...">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <DigestValue>...omissis...</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>...omissis...</SignatureValue>
            <KeyInfo>
                <wsse:SecurityTokenReference xmlns="">
                    <wsse:Reference URI="#SecurityToken-...omissis..." ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" />
                </wsse:SecurityTokenReference>
            </KeyInfo>
        </Signature>
    </wsse:Security>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body wsu:Id="..." xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <SOAP-ENV:Fault>
      <faultcode>wsse:FailedCheck</faultcode>
      <faultstring>The signature or decryption was invalid</faultstring>
      <detail>
        <e:myfaultdetails xmlns:e="Some-URI">
          <errorCode>500</errorCode>
          <message>INTERNAL_SERVER_ERROR</message>
        </e:myfaultdetails>
      </detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

After doing some research i've read that to provide a BinarySecurityToken as requested i need to implement a customBinding. I've tried different approaches and combinations but i always fail to make progress.

For example, by using this custom behaviour:

  <customBinding>
    <binding name="cb">
      <security authenticationMode="MutualCertificateDuplex" requireDerivedKeys="false" includeTimestamp="true"
        messageProtectionOrder="EncryptBeforeSign" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" />
      <textMessageEncoding messageVersion="Soap11" />
      <httpsTransport />
    </binding>
  </customBinding>

I receive an Internal server error like this:

ExceptionType: System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.InnerException: System.ServiceModel.FaultException:Internal Error

and, most important...my outgoing request is ALWAYS the same as the basicHttpBinding one! Obviously i have not well understood something. I can see that, using the basicHttpBindig i can correctly communicate with them, but i fail to provide the required security fragments. If i try to use any other king of binding (for example wsHttpBinding or a customBinding) i receive an error message. Can someone please help me understanding the correct way to do such job? any help would be very appreciated.

Thanks a lot.

EDIT:

I'm adding the outgoing request:

<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>
    <ActivityId CorrelationId="dd479557-7e51-41de-822b-d2ac669ff827" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">bbd2f92b-33d5-4ec0-87b6-690f2142cdf5</ActivityId>
    <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="uuid-7b22e181-f551-4821-91e0-cf8c9b8d9eef-1">
        <u:Created>2013-09-09T12:24:03.563Z</u:Created>
        <u:Expires>2013-09-09T12:29:03.563Z</u:Expires>
      </u:Timestamp>
      <o:BinarySecurityToken>
        <!-- Removed-->
      </o:BinarySecurityToken>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
          <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
          <Reference URI="#_1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
            <DigestValue>...omissis...</DigestValue>
          </Reference>
          <Reference URI="#uuid-7b22e181-f551-4821-91e0-cf8c9b8d9eef-1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
            <DigestValue>...omissis...=</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>...omissis...</SignatureValue>
        <KeyInfo>
          <o:SecurityTokenReference>
            <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-e31a3eed-6ac7-4dcb-bfb2-2384764acd93-2"></o:Reference>
          </o:SecurityTokenReference>
        </KeyInfo>
      </Signature>
    </o:Security>
  </s:Header>
  <s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <CPCUValidityRequest xmlns="http://......omissis...">
      <serviceType>3</serviceType>
      <arg1>arg1</arg1>
      <arg2>arg2</arg2>
      ...omissis...
    </CPCUValidityRequest>
  </s:Body>
</s:Envelope>

Solution: Actually i can't successfully invoke the remote service due to an error (as stated in the comments to the accepted solution. But i can say that this question is answered due to the fact that i've managed to create a request mostly similar to the required one. Many thanks to Yaron.

PS:( An hint for those who will have a similar issue, to check the outgoing/incoming request, try to use the Microsoft Trace Viewer, enabling tracing as suggested in this answer https://stackoverflow.com/a/11678740/2274007 (remember to follow also the advice in the comment))

Was it helpful?

Solution

Please publish your outgoing request. In your binding I would change to authenticationMode="mutualCertificate". Otherwise it looks good.

Also in order to send just signed message and not encrypted one add this attribute on top of your data contract (reference.cs):

[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.SimpleServiceSoap", ProtectionLevel=System.Net.Security.ProtectionLevel.Sign)]

More details on this approach in this wcf security tips article.

OTHER TIPS

Try this customBinding:

 <customBinding>
    <binding name="cb">
      <security authenticationMode="MutualCertificateDuplex" 
                defaultAlgorithmSuite="Basic128Rsa15" 
                requireDerivedKeys="false"
                enableUnsecuredResponse="true"
                messageProtectionOrder="EncryptBeforeSign" 
                messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10">
      </security>
      <textMessageEncoding messageVersion="Soap11WSAddressing10"/>
    <httpsTransport />
    </binding>
  </customBinding>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top