Sending requests to Java web service in WCF .NET with WS Security

Viewed 109

I have a .NET application which needs to communicate with a 3rd party Java SOAP web service. The Java service uses WS Security. I have instructions on how to call this web service from SoapUI, and am able to successfully send requests. I am having a difficult time trying to implement this configuration in WCF so that I can send requests to the Java web service.

I have been able to send the request in SoapUI, and here is what it sends:

<s:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <ds:Signature Id="SIG-252F850CD1BCBD83AA1631965258295205"
            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 u"
                        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="#id-252F850CD1BCBD83AA1631965258295204">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                            <ec:InclusiveNamespaces PrefixList="u"
                                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>digest value...</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue> signature... </ds:SignatureValue>
            <ds:KeyInfo Id="KI-252F850CD1BCBD83AA1631965258295202">
                <wsse:SecurityTokenReference u:Id="STR-252F850CD1BCBD83AA1631965258295203">
                    <ds:X509Data>
                        <ds:X509IssuerSerial>
                            <ds:X509IssuerName>CN=certname</ds:X509IssuerName>
                            <ds:X509SerialNumber>12345</ds:X509SerialNumber>
                        </ds:X509IssuerSerial>
                    </ds:X509Data>
                </wsse:SecurityTokenReference>
            </ds:KeyInfo>
        </ds:Signature>
    </wsse:Security>
</s:Header>

Here is the configuration in SoapUI: I create a project in SoapUI using the web service URL. I then add a keystore to the webservice that references a .jks file. Then I add an Outgoing WS-Security Configuration of type Signature with the keystore.

SoapUI Outgoing Security Configuration

On the web service binding in SoapUI, in the Authorization tab, I choose Basic Authorization and set Outgoing WSS to that outgoing security configuration.

SoapUI Basic Authorization Configuration

Once that is done, I can send requests.

Does anyone know how to reproduce this configuration in WCF? I have something started, but it seems at least that the KeyInfo element is missing X509IssuerSerial data. There may be more pieces that I am missing, however.

Here is my WCF Configuration:

      <customBinding>
    <binding name="DigitalSignature">
      <textMessageEncoding messageVersion="Soap12" />
      <security defaultAlgorithmSuite="Basic128Rsa15" enableUnsecuredResponse="true"
                authenticationMode="MutualCertificate" includeTimestamp="false"
                messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
      </security>
      <httpTransport />
    </binding>
  </customBinding>

And it produces this for the security header:

<o:Security s:mustUnderstand="1"
        xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <o:BinarySecurityToken u:Id="uuid-f59660cb-85d1-476a-9e3a-366c8c2d9d21-2" 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">binary token...</o: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="#uuid-8c2cf70c-95bf-44f2-989c-a2b8d1385319-1">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>digest...</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>signature...</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-f59660cb-85d1-476a-9e3a-366c8c2d9d21-2"/>
                </o:SecurityTokenReference>
            </KeyInfo>
        </Signature>
    </o:Security>
</s:Header>
1 Answers

I know that my question was very specific. I noticed that the SecurityTokenReference element in the XML produced by my WCF configuration wasn't the correct shape. I did some searching and it seems configuring the X509IssuerSerial must be done in code rather than in the app config. I was able to get this to work by creating a custom Binding class. Here is what ended up working for me:

        public MyServiceBinding()
        {
            var initiator = new X509SecurityTokenParameters(
                X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.Never);
            var recipient = new X509SecurityTokenParameters(
                X509KeyIdentifierClauseType.IssuerSerial, SecurityTokenInclusionMode.Never);
            var securityBinding = new AsymmetricSecurityBindingElement(initiator, recipient)
            {
                IncludeTimestamp = false,
                SecurityHeaderLayout = SecurityHeaderLayout.Lax,
                MessageSecurityVersion = MessageSecurityVersion
                    .WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12,
                DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic128Rsa15,
                MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt,
                EnableUnsecuredResponse = true
            };
            securityBinding.SetKeyDerivation(false);
            securityBinding.IncludeTimestamp = false;
            securityBinding.AllowInsecureTransport = true;
            securityBinding.LocalClientSettings.DetectReplays = false;
            Elements.Add(securityBinding);

            //Message Encoding
            var textMessageEncoding = new TextMessageEncodingBindingElement();
            textMessageEncoding.MessageVersion = MessageVersion.Soap12;
            textMessageEncoding.WriteEncoding = Encoding.UTF8;
            Elements.Add(textMessageEncoding);

            //Transport Binding
            var httpTransport = new HttpTransportBindingElement();
            Elements.Add(httpTransport);
        }

Maybe someone will be in the same boat at some point and find this helpful.

Related