Fork me on GitHub Icon (hidden image)
JeyDotC

Comunicating Jax-ws client with WCF service with server sertificate

17 October 2013

This article is about comunicating a jax-ws client with a WCF service using certificates having these conditions:

  • The WCF binding is wsHttpBinding.
  • WCF security is at Message.
  • The library used in client side is jax-ws.
  • The client have been generated with WSIMPORT (Wsimport tutorial, Wsimport in netbeans).

This is the <system.serviceModel> part of the web.config file for the WCF service I was trying to comunicate:

...
<system.serviceModel>
    <services>
        <service name="WSBindingService.Service1" behaviorConfiguration="Service1Behavior" >
            <endpoint address="" 
                      binding="wsHttpBinding" 
                      bindingConfiguration="Binding1" 
                      contract="WSBindingService.IService1"  />        
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>

    <bindings>
        <wsHttpBinding>
            <binding name="Binding1" >
                <security mode="Message">
                    <message clientCredentialType="None" negotiateServiceCredential="false" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>

    <behaviors>
        <serviceBehaviors>
            <behavior name="Service1Behavior">
                <serviceMetadata httpGetEnabled="True"/>
                <serviceCredentials>
                    <serviceCertificate findValue="put your certificate subject or serial here"
                                        storeLocation="LocalMachine"
                                        storeName="My" />
                    <clientCertificate>
                        <authentication certificateValidationMode="PeerTrust"  />
                    </clientCertificate>
                </serviceCredentials>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

NOTE: In my case I used netbeans as my IDE for the client, but it is not required, if anyone can reproduce these steps in eclipse and have a post about it, I'd like to add a link to that post.

The current situation

One day your boss tells you "Johny, I need a WCF service and a java client" you creates them and everything goes good until he says, "I need certificates!" I gess this image illustrates the situation:

Java and .NET don't want to talk :(

Once certificates come in play, a myriad of errors pops up in front of you, one of the worst ones is having your client indefinitely trying to talk to the service, no exceptions, zero explosions, nothing that can give you a clue on what is going on.

The long road to the solution

Step 1: Configure your keystore and add it to your client

The first thing is to have your certificates in your project's keystore, there are several ways to do this, that depends on your certificates set. In this case I had a CA signed private certificate (.pfx) from which one can export a public certificate (.cer) the latter is the one we're interested in, to import it one can use this command:

keytool -keystore "path/to/mykeystore.jks" -importcert -alias some_alias -trustcacerts -file "path/to/myCertificate.cer" -keypass yourcertificate_password -storepass mykeystore_password

Once you have your keystore ready, you will need to add a reference to it in your webservice client. Netbeans users may refer to this tutorial.

Step 2: Install METRO, the latest version!

Configuring my keystore wasn't enough, errors appeared here and there, if my memory doesn't fail, in that moment the client tried to send the messages ignoring any server side security configuration, also, those were the horrible moments of the client trying to talk to the server and sticking forever in it's futile attempt.

After a lot of research (mostly in stackOverflow), a promising solution appeared, the Metro library which is intended to mend faces between Java and .Net, one just need to reference it and it was supposed to do the rest.

Note: Remember to remove any previous reference to jax-ws as that library is included with Metro.

But then, a meaningless NullPointerException appeared, those were two or three days cursing certificates and viewing this stackOverflow question unanswered. Then I realized that the library version (automatically added by netbeans) was 2.0, updating to the 2.3 version changed the situation, a meaningful exception were thrown and then I could go on, never felt so happy to seeing an exception before!

Step 3: Install BouncyCastle

The exception thrown was:

Exception: "algorithm is not supported for key encryption java.security.NoSuchAlgorithmException: Cannot find any provider supporting RSA/ECB/OAEPPadding"

The answer were found here. Apparently, the standard Java installation was missing some encryption algorithms, so it was necessary to install them.

All I had to do was to download this library, add it to the project and add this line of code before calling the service:

Security.addProvider(new BouncyCastleProvider());

Step 4 (hopely the last): Install the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"

Once the encryption algorithm obstacle were passed, the next problem appeared:

Java Security: Illegal key size or default parameters

Man! after a week of problems one feels like Sisyphus!. Fortunately the solution were found by someone else and is here.

Apparently the Java Cryptography Extension (JCE) Jurisdiction Policy Files that comes with the JRE have some kind of limit for something (I don't know what or where and I don't care), it was necessary to replace them with the Unlimited Strength version which can be downloaded here for Java 6 and here for Java 7, make sure to download the correct version for your JRE.

To install them, go to your JRE installation folder and go to the '/lib/security' folder, backup the files inside it and replace them with the ones you just downloaded. Detailed instructions can be found in the README.txt file that comes with the download.

Praise the Lord! Java and .NET finally talked to each other after 8 or 9 days of agony.

Summary

In order to comunicate Java and WCF one must:

  1. Configure the keystore and add it to the client.
  2. Install METRO and be sure to install the latest version.
  3. Install BouncyCastle and add the provider by calling Security.addProvider
  4. Install the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"

I hope this article saves some lives, it has a lot of room for improvement, but it may give you clues to point to the right direction, thanks for reading :D

TODO in this article

  • Reference a good article about keystore configuration.
  • Paste the WCF's web.config file to illustrate the wsBinding used in this case.