简体   繁体   中英

WCF client consumes JAVA web service - should I use WCF or just create a custom parser/message factory?

We've a business partner who requires us to create a service request message with a SAML 2.0 assertion. The partner's supplied two certificates and a test harness for their JAVA webservice.

I've created a WCF client with a CustomBinding to try and recreate the request and consume the service, but I'm getting so frustrated with the nuances of WCF (and the lack of intrinsic support for SAML 2.0) I'm wondering am I better off using something like a WebClient or HttpWebRequest and encrypting/building & signing the XML web request and doing the same for the response. I know there's a lot of work involved on this but at least I'd be in full control.

Your advice would be very much appreciated, what I'm working with is displayed below

Note: I was supplied with a SoapUI Test harness for the Java service

The vendor supplied me with this request (ran though SOAPUI and extracted via Fiddler)

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
  <SOAP-ENV:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <xenc:EncryptedKey Id="EncKeyId-29B98C291D1FDFB39113352984774895">
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
          <wsse:SecurityTokenReference>
            <ds:X509Data>
              <ds:X509IssuerSerial>
                <ds:X509IssuerName>CN=test_server</ds:X509IssuerName>
                <ds:X509SerialNumber>12356789</ds:X509SerialNumber>
              </ds:X509IssuerSerial>
            </ds:X509Data>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
        <xenc:CipherData>
          <xenc:CipherValue>
            <!--Omitted -->
          </xenc:CipherValue>
        </xenc:CipherData>
        <xenc:ReferenceList>
          <xenc:DataReference URI="#EncDataId-3"/>
        </xenc:ReferenceList>
      </xenc:EncryptedKey>
      <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#X509v3" wsu:Id="CertId-29B98C291D1FDFB39113352984773591" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><!--Omitted --></wsse:BinarySecurityToken>
      <ds:Signature Id="Signature-1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#id-2">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>
              <!--Omitted -->
            </ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>
          <!--Omitted -->
        </ds:SignatureValue>
        <ds:KeyInfo Id="KeyId-29B98C291D1FDFB39113352984773792">
          <wsse:SecurityTokenReference wsu:Id="STRId-29B98C291D1FDFB39113352984773893" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Reference URI="#CertId-29B98C291D1FDFB39113352984773591" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
    </wsse:Security>
    <saml:Assertion ID="_54d0c8395de26c3e44730df2c9e8d3e9" IssueInstant="2012-02-17T10:40:36.806Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
      <saml:Issuer>CN=test_client</saml:Issuer>
      <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="#_54d0c8395de26c3e44730df2c9e8d3e9">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>
              <!--Omitted -->
            </DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>
          <!--Omitted -->
        </SignatureValue>
        <KeyInfo>
          <X509Data>
            <X509Certificate>
              <!--Omitted -->
            </X509Certificate>
          </X509Data>
        </KeyInfo>
      </Signature>
      <saml:Subject>
        <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">joe.bloggs@facility.ie</saml:NameID>
      </saml:Subject>
      <saml:Conditions NotBefore="2012-02-17T10:40:21.806Z" NotOnOrAfter="2012-02-17T10:41:06.806Z"/>
    </saml:Assertion>
    <wsa:Action SOAP-ENV:mustUnderstand="1">http://www.xxxxxxx.xxx/ws/schemas/xxxxxx1/xxxx/xxxxxxxxxxxxxx</wsa:Action>
    <wsa:MessageID SOAP-ENV:mustUnderstand="1">uuid:bffc27ba-68d9-44e6-b1f0-e2f852df7715</wsa:MessageID>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body wsu:Id="id-2" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <xenc:EncryptedData Id="EncDataId-3" Type="http://www.w3.org/2001/04/xmlenc#Content">
      <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <wsse:Reference URI="#EncKeyId-29B98C291D1FDFB39113352984774895"/>
        </wsse:SecurityTokenReference>
      </ds:KeyInfo>
      <xenc:CipherData>
        <xenc:CipherValue>
          <!--Omitted -->
        </xenc:CipherValue>
      </xenc:CipherData>
    </xenc:EncryptedData>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

This is as close as I've gotten with my WCF client. Issues I can immediatley is that the <o:SecurityTokenReference> element should contain the Issuer and Serial, instead it contains a KeyIdentifier element?

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/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" u:Id="_3"/>
    <a:MessageID u:Id="_4">urn:uuid:fc8ef84b-dbf5-4150-a0c3-d4cc986333d1</a:MessageID>
    <ActivityId CorrelationId="a9e1fec4-32bc-4633-909e-3d601c809b3c" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">d1909115-8922-46f3-a96c-db15bf91c599</ActivityId>
    <a:ReplyTo u:Id="_5">
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo27oY4/3mnBOry0YL4StqvcAAAAA0UM+eVt4fU2AOe9/B3lPDZNf/2HmAuNEvzAoW0eKVSUACQAA</VsDebuggerCausalityData>
    <a:To s:mustUnderstand="1" u:Id="_6">https://localhost:8089/ws</a:To>
    <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-e5592f06-32af-40fb-996e-a0a469c7ed5e-2">
        <u:Created>2012-04-24T20:41:50.447Z</u:Created>
        <u:Expires>2012-04-24T20:46:50.447Z</u:Expires>
      </u:Timestamp>
      <e:EncryptedKey Id="uuid-e5592f06-32af-40fb-996e-a0a469c7ed5e-1" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
        <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <o:SecurityTokenReference>
            <o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">lU10DQn4lSpE4fRpE9gslm5QDt0=</o:KeyIdentifier>
          </o:SecurityTokenReference>
        </KeyInfo>
        <e:CipherData>
          <e:CipherValue>
            <!--Omitted-->
          </e:CipherValue>
        </e:CipherData>
        <e:ReferenceList>
          <e:DataReference URI="#_2"/>
          <e:DataReference URI="#_7"/>
          <e:DataReference URI="#_8"/>
        </e:ReferenceList>
      </e:EncryptedKey>
      <o:BinarySecurityToken u:Id="uuid-fad0c01f-ab4b-4a5f-bec6-93aa8c2d5a52-1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"><!--Omitted--></o:BinarySecurityToken>
      <e:EncryptedData Id="_7" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
        <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
        <e:CipherData>
          <e:CipherValue>
            <!--Omitted-->
          </e:CipherValue>
        </e:CipherData>
      </e:EncryptedData>
      <e:EncryptedData Id="_8" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
        <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
        <e:CipherData>
          <e:CipherValue><!--Omitted--></e:CipherValue>
        </e:CipherData>
      </e:EncryptedData>
    </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">
    <e:EncryptedData Id="_2" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
      <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
      <e:CipherData>
        <e:CipherValue><!--Omitted--></e:CipherValue>
      </e:CipherData>
    </e:EncryptedData>
  </s:Body>
</s:Envelope>

Using this configuration for the WCF CustomBinding

<system.serviceModel>        
        <bindings>
          <customBinding>
            <binding name="WSHttpBinding_IEnquiryRequest" >
              <transactionFlow />
              <security defaultAlgorithmSuite="TripleDesRsa15"
                        authenticationMode="MutualCertificate" 
                        messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" 
                        requireDerivedKeys="false"
                        >

                      <secureConversationBootstrap authenticationMode="CertificateOverTransport" 
                                           messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" 
                                           requireDerivedKeys="false" />
              </security>
              <textMessageEncoding messageVersion="Soap11WSAddressing10" />
              <!--<mtomMessageEncoding messageVersion="Soap11WSAddressing10" />-->
              <httpsTransport requireClientCertificate="true" />
            </binding>
          </customBinding>            
        </bindings>
      <behaviors>
        <endpointBehaviors>
          <behavior name="certBehaviour">            
              <clientCredentials>
                <!-- clientCertificate not defaultCertificate -->
                <clientCertificate x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" findValue="test_client" />
                <serviceCertificate>
                  <defaultCertificate x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" findValue="test_server"/>
                  <authentication revocationMode="NoCheck" certificateValidationMode="None"  />
                </serviceCertificate>
              </clientCredentials>            
          </behavior>
        </endpointBehaviors>
      </behaviors>
        <client>
          <endpoint
               address="https://localhost:8089/pvs/ws"
               binding="customBinding"
               bindingConfiguration="WSHttpBinding_IEnquiryRequest"
               contract="XXXService.enquiryRequest"
               name="WSHttpBinding_IEnquiryRequest"
               behaviorConfiguration="certBehaviour"
               >
            <identity>
              <dns value="test_server"/>
            </identity>
          </endpoint>
        </client>
    </system.serviceModel>

I've no idea how to insert the SAML 2.0 assertion in there before it's signed. That and the Key Issuer/serial issue above is where my main problems lie with the request.

Any and all help appreciated

Was able to get there in the end with help from Yaron over on the WCF forums

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/9a1db0bb-d632-4f11-80b4-fab78be3a3ee

Was difficult but got there in the end, to think I was going to write it from scratch at one point!

如果您没有在XP上运行, WIF支持SAML 2.0令牌格式。

I used a sample XML template instead of doing it all in code, but that's possible too.

Note: You need to add this to the message using a Custom Encoder - that way you can just slot in the SAML token into the header (only header elements are signed, not the content)

I'm in a bit of a rush, let me know if you need more info

    private void SignSaml()
    {
        RSACryptoServiceProvider rsaProvider = (RSACryptoServiceProvider)SecurityController.ClientCertificate.PrivateKey;


        //Load the private key from xml file
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(_samlTextWithElementValues);            

        // Create a SignedXml object.
        SignedXml signedXml = new SignedXml(xmlDocument);

        //Specify the canonicalization method
        signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
        // Add the key to the SignedXml document.
        signedXml.SigningKey = rsaProvider;

        // Add the x509 data to the signature
        KeyInfo keyInfo = new KeyInfo();
        KeyInfoX509Data keyInfoClause = new KeyInfoX509Data(SecurityController.ClientCertificate, X509IncludeOption.None);
        keyInfoClause.AddCertificate(SecurityController.ClientCertificate);
        keyInfo.AddClause(keyInfoClause);
        signedXml.KeyInfo = keyInfo;
         // Create a reference to be signed.
        Reference reference = new Reference("#_54d0c8395de26c3e44730df2c9e8d3e9");

        //reference.Uri = ;

        // Add an enveloped transformation to the reference.
        XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
        reference.AddTransform(env);
        reference.AddTransform(new XmlDsigExcC14NTransform());

        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);

        // Compute the signature.
        signedXml.ComputeSignature();

        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Append the element to the XML document.
        xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(xmlDigitalSignature, true));
        _samlSignedWithCertificate = xmlDocument.InnerXml;
    }

Added config as per request

<customBinding>
    <binding name="BINDING" >
      <transactionFlow />
      <security defaultAlgorithmSuite="TripleDesRsa15"
                authenticationMode="MutualCertificate"
                messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"
                requireDerivedKeys="false"
                messageProtectionOrder="SignBeforeEncrypt">
        <secureConversationBootstrap authenticationMode="CertificateOverTransport"
                messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                requireDerivedKeys="false" />
      </security>
      <httpsTransport requireClientCertificate="true" />
    </binding>
  </customBinding> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM