Friday, February 13, 2004 | |
Securing a Web Service - Client SSL Now that we have a secured the server with SSL, secured the service with basic authentication and added valid users to our JAAS XML provider, we need to create a client capable of sending this information to the server using SSL. The quick and simple expectation is that all you have to do is change the URI used in the client from http://127.0.0.1:8888/ws/EchoService to https://127.0.0.1:4443/ws/EchoService. Try it out. If you are running on a machine with an OracleAS install on it, it probably will work. If you are on a client machine on which there is no OracleAS installed (for example, just JDeveloper) you will likely get this error: java.lang.UnsatisfiedLinkError: no njssl9 in java.library.path The njssl9.dll or njssl9.so files are Oracle's SSL implementation. You have two choices ... if you run the client in an OracleAS environment, you are set - this file will be found. If you aren't, you need to think about using Sun's JSSE which will help you out. As I am running in JDeveloper which has a built in JDK, I am going to do two things to deal with this. First, switch it over to Sun's JDK for the runtime (the reason here is so that I have an client JDK representative of a non-Oracle environment - the built in JDK in JDeveloper is specific to JDeveloper) and second swap out Oracle's SSL libraries for JSSE from Sun's JDK (so you don't have the njssl9.* dependencies). Note again I am using JDK 1.4.1 which has JSSE built in. Here are the steps: 1. Run JDeveloper using a native JDK rather than the JDK it ships with. To do this go to your project properties under the library node ((menu Project->Properties->Libraries) and create a new J2SE runtime version using <JAVA_HOME>\jdk\bin\java.exe as the entry. This will make JDeveloper use the native JDK to run applications rather than its embedded JDK. Here are some pictures showing what I have done: 2. Create a new client library within JDeveloper (menu Project->Properties->Libraries) containing all the same jars as the existing Oracle SOAP entry but replacing all the jssl-1_2.jar and javax-ssl-1_2.jar files with the JSSE library from the native Sun JDK. The existing Oracle SOAP libraries looks like this: Oracle SOAP: My modified version looks like this - note the key change is that I replaced the Oracle SSL libraries with jsse.jar from Sun's JDK: JSSESOAP: C:\jdk1.4.1\jre\lib\jsse.jar;
Now we are almost in business. But, run the client again and you will experience no joy :-( You likely will get an error message like this: [SOAPException: faultCode=SOAP-ENV:IOException; msg=java.security.cert.CertificateException: Couldn't find trusted certificate; targetException=javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: Couldn't find trusted certificate No worries! This one is easy to solve. What's happened now is that your client JDK (in this case the client is JDeveloper using a regular JDK) is looking at its list of trusted certificates and the one we created for OC4J previously is not in its trusted key store. 1. Run the command: 2. Next, for the JDK we will be using to run the client (in my case the same as the server), we need to import this certificate as a trusted party into the keystore. Let's start this last bit by copying server.cer to <JAVA_HOME>\jre\lib\security: 3. Next let's import this certificate into a new client keystore, called client.keystore. The act of importing will create the keystore: <JAVA_HOME>\jre\bin\keytool -import -v -trustcacerts -alias oc4j-sv
Finally, the same client we ran in this blog entry Securing a Web Service - BASIC AUTH here should again run successfully with one last change - I have to add this bit of code to my Web service stub: <Note-March 4> <JAVA_HOME>\jre\bin\keytool -import -v -trustcacerts -alias oc4j-sv I assume it is just that I have have a syntax problem in the stub with this line: which is no longer required in the stub because "cacerts" is the default keystore for the JDK. I have tried quite a few variations to fix this to no avail :-( - next time I revisit this, I will try -D options on the JDK rather than System.setProperty. </Note-March 4> So what have we managed to do here? First, our basic authentication continues to work it is just now that when we send our password over the wire, we are using SSL to encrypt it. Further, by using JSSE we can now use any arbitrary Java client and not be dependent on Oracle's SSL libraries (though in this case I continued to use Oracle SOAP - but the heavy lifting of getting rid of the SSL dependency is done). With SSL there is of course one more step I can do which is to use client certificates too. That is of course a topic for another day! comment [] 12:02:26 AM |