Kristian Kristensen’s Blog


Getting WCF to talk to a Java AXIS 1.X and WSS4J Web Service – Part 3 of 3

Posted in Code,WCF by Kristian Kristensen on the December 20th, 2010

This is the third post in a series on my woes in integrating to a Java AXIS 1.X and WSS4J web service. Read Part 1, Part 2, Part 3.

Setting up the second type of service calls with its separate security configuration also had its quirks. The service semantics require Usernames with a password, but it specifically does not want WS-Security timestamps. Via MSDN forums I found this post by Kjell-Sverre Jerijærvi in which he details how to turn off the inclusion of the timestamp. His approach required code however, and I prefer to be able to do it all in the configuration. The problem with that is that the “includeTimestamp” attribute is not available on the Basic HTTP binding. Therefore I needed to convert the default out of the box Basic HTTP binding into a Custom Binding upon which I can control the “includeTimestamp” attribute. This post details the BasicHttpBinding equivalent CustomBinding. Based on that I devised the following custom binding.

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

The client endpoint that connects the binding is seen below. It’s completely standard and out of the box.

 <endpoint address="https://the-external-service-url.dk"
        binding="customBinding" bindingConfiguration="SkatUserNameToken"
        contract="IContract"
        name="BestillingHent" />

When calling the service you need to set the Username and Password on the client in ClientCredentials property. This is used by WCF when it includes the username and password in the WS Security header elements.

client.ClientCredentials.UserName.UserName = USERNAME;
client.ClientCredentials.UserName.Password = PASSWORD;

This completes my little series on getting WCF to talk to a Java AXIS 1.X and WSS4J web service exposed by a public institution in Denmark (Skat eIndkomst).
Let me know if you have any comments or questions.

  • If you like my writing you should subscribe to my RSS feed.

    Getting WCF to talk to a Java AXIS 1.X and WSS4J Web Service – Part 2 of 3

    Posted in Code,WCF by Kristian Kristensen on the December 12th, 2010

    This is the second post in a series on my woes in integrating to a Java AXIS 1.X and WSS4J web service. Read Part 1, Part 2, Part 3.

    The first service interaction requires signing the message, timestamping it and include the certificate that the request should be signed with in a BinarySecurityToken. The key discovery was in this forum thread that lead me to using the mutualCertificate option for the authentication method as well as where to tweak the timestamp inclusion. With this in place I could call my service and get to the next step. This was a policy error on the WCF side meaning my client that the order of the returned security elements didn’t line up. This was a major breakthrough because it meant that I was now calling the service from WCF. Via Fiddler I could also see what was going over the wire and that the returned data was in fact valid! Solving the exception I received on my WCF side proved to be fairly easy. WCF is strict in enforcing the order that the WS-Security elements appear in the response, but OOB an attribute (“securityHeaderLayout”) is provided that relaxes this requirement (Incorrect order of security elements “lax”).
    The full binding configuration is seen below.

    <customBinding>
            <binding name="SkatSignatureTimestamp">
              <textMessageEncoding messageVersion="Soap11" />
              <security allowSerializedSigningTokenOnReply="true" authenticationMode="MutualCertificate"
                requireDerivedKeys="false" securityHeaderLayout="Lax" includeTimestamp="true"
                keyEntropyMode="ClientEntropy" messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                requireSecurityContextCancellation="false">
                <secureConversationBootstrap />
              </security>
              <httpsTransport />
            </binding>
            </customBinding>
    

    To configure the certificates used to sign an endpoint behavior needs to be applied. I’ve been given a test certificate that I can use by the service vendor and I imported it to my computers certificate store. Then configuring the certificates used was fairly easy. The behavior is seen below.

              <behaviors>
          <endpointBehaviors>
            <behavior name="SkatCertificates">
              <clientCredentials>
                <clientCertificate findValue="xx xx xx xx" x509FindType="FindByThumbprint" />
                <serviceCertificate>
                  <!--
         Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
         is in the user's Trusted People store, then it will be trusted without performing a
         validation of the certificate's issuer chain. This setting is used here for convenience so that the
         sample can be run without having to have certificates issued by a certificate authority (CA).
         This setting is less secure than the default, ChainTrust. The security implications of this
         setting should be carefully considered before using PeerOrChainTrust in production code.
         -->
                  <defaultCertificate findValue="xx xx xx" x509FindType="FindByThumbprint" />
                  <authentication certificateValidationMode="PeerOrChainTrust" />
                </serviceCertificate>
              </clientCredentials>
            </behavior>
          </endpointBehaviors>
        </behaviors>
        

    Setting up the client section is a matter of coupling the binding configuration with the behavior configuration. The thing to remember is the “identity” element that needs to match up with the identity in the certificate used, ie. the certificate alias. You can find this name by opening the certificate in Certificate Manager in Windows and look for the value of “Issued To”.

    <client>
          <endpoint address="https://the-external-service-url.dk"
            behaviorConfiguration="SkatCertificates" binding="customBinding"
            bindingConfiguration="SkatSignatureTimestamp" contract="IContract"
            name="Service">
            <identity>
              <dns value="certificate identity" />
            </identity>
          </endpoint>
          </client>
    

    Calling the service now will result in an error. The problem was that the SOAP body is being encrypted and the service expects the message to only be signed. Fixing this is done by adding an attribute to the ServicePortType interface automatically generated by the “Add Service Reference” in Visual Studio. The attribute that needs to be set is the ProtectionLevel attribute:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(Namespace = "http://rep.oio.dk/skat.dk/eindkomst/",
      ConfigurationName = "Service_IServicePortType",
      ProtectionLevel = ProtectionLevel.Sign
    ]
    public interface IndkomstOplysningKlassiskAbonnentHent_IServicePortType {
       //interface implementation
    }
    

    This instructs WCF to only Sign the message. Other values of ProtectionLevel are None, and EncryptAndSign. Issuing the service call now results in a correct message to be sent over the wire.

    The next part deals with the second type of service call I had to make, which had its own set of security requirements.

  • If you like my writing you should subscribe to my RSS feed.

    Getting WCF to talk to a Java AXIS 1.X and WSS4J Web Service – Part 1 of 3

    Posted in Code,WCF by Kristian Kristensen on the December 6th, 2010

    This is the first post in a series on my woes in integrating to a Java AXIS 1.X and WSS4J web service. Read Part 1, Part 2, Part 3.

    I’m currently working on a project where I need to integrate with a system exposing a web service. I don’t know the exact technology used by the system but I believe it’s an Apache Axis 1.X and WSS4J stack intermingled with some BEA. My client is a .NET shop, so it would be prefereable to use .NET on the receiving side. Furthermore WCF is already in use by my client, and so it would be prefereable to do the integration using WCF as the technology stack. The possibilty of success with this approach was complicated by the fact that others had previously tried to integrate with the external system using .NET/WCF and had quite a bit of trouble with it. I went through quite a bit of trial and error while trying to integrate to this system and hence wanted to collect my experiences in a blog post for others to use.

    The external system is a web service exposed by the Danish IRS (Skat) to retrieve income data for people being taxed in Denmark (eIndkomst). There are obivously very strict rules and regulation in place for who can get access to this system and what data you can access. Therefore this is by no means a publicly available system. The service utilizes the OIO service schemas (OIOXML) being used by the public government in Denmark as its datamodel.

    The external web service uses a couple of different means for achieving security. SSL is used for all calls and depending on the call a different WS-Security configuration is used. This means an interplay of Certificate Signing, Timestamping and using Username Tokens.
    The system owner has the following client-config.wsdd file in their documentation:

    <requestFlow>
          <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
        	<parameter name="action" value="Signature Timestamp"/>
    <parameter name="passwordCallbackClass"
     	value="xxx.xxx.xxx.PasswordCallbackHandler"/>
        	<parameter name="signatureKeyIdentifier" value="DirectReference" />
        	<parameter name="signaturePropFile" value="xxxxx.properties" />
          </handler>
        </requestFlow>
        <responseFlow>
          <handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
    	  <parameter name="action" value="Signature Timestamp"/>
    	  <parameter name="passwordCallbackClass"
    		value="xxx.xxx.xxx.PasswordCallbackHandler"/>
       	  <parameter name="signatureKeyIdentifier" value="DirectReference" />
    	  <parameter name="signaturePropFile" value="xxxx.properties"/>
          </handler>
        </responseFlow>
    

    My initial thoughts were to create a demo client using Java to make sure that my calls went through. Then with this foundation I could try implementing an integration using WCF. Should this fail, I could always utilize a bridge between a Java client and .NET. In order to minimize the number of differences I matched my client stack to the external systems stack. Implementing this test client was also a return to Eclipse and Java, which I haven’t done much off since leaving University. Getting the initial requests flowing, getting a request generated and shipped off the to external system was fairly easy. But then the trouble started. The external sysetm wouldn’t acknowledge my security signature, and returned an error about signing.

    Parallel with my efforts in a getting a custom Java client to work I also used SoapUI for a much simpler “does it work” test. This tool was new to me, but it’s really a nifty tool! You can point it to a WSDL endpoint and it will suck down all the schemas and generate test requests. Afterwards you can configure WS-Security, Reliable Messaging and a bunch of other things. A more advanced use of the tool allows you to do unit testing of services.

    Now I could get SoapUI to work, replaying different requests that were supplied to me by the external system owner, as well as requests I handcradfted myself. But my Java client simply would not work. Using the XML that went over the wire from my Java client I could compare it to what worked via SoapUI as well as what was supplied by the system owner. The objects were practically equal. The Java client XML when copied into SoapUI also worked. The WS-Security headers being generated were correct and similar to what was expected by the external system. However what was different was the way namespaces and their prefixes were layed out.
    In the XML generated by the Java client it was much more verbose and included namespaces and prefixes on practially every element. My problem was signature validation and so the way namespaces and their prefixes are laid out and when they’re added is important. The signature is taken of the body of the Soap envelope and so if the two ends doesn’t perform this signature creation and re-generation in the same way it’ll fail. Googling issues with this problem and the errors returned when using WSS4J and Axis didn’t really help much. There were some issues that were highly emphasized, namely to disable namespace optimizations, not retrieve the Soap Message, etc. But none of it helped or alleviated my problem. Then I found a mailling list post talking about issues in the way canonicalization is done in WSS4J that trips up the security processing.

    I don’t know if this is problem with Axis/WSS4J in and of itself, or the way that the external systems Schemas are laid out. However, the end result was the same: no connection.

    It basically led me to the conclusion that this was a tougher problem than I had anticipated. At this point I faced trying another Java stack or give WCF a go. I hadn’t had much luck with my Java adventure and so thought “I’ll timebox a WCF spike and see how far I get”. So that’s what I did.

    The next post in this series explains how I got WCF to talk to the first service.

  • If you like my writing you should subscribe to my RSS feed.