Friday, November 2, 2012

Initiating web service objects using class files

If you want to call a webservice which uses more complex arguments then it's easier (or even best practice) to use class files in stead of recreating the objects by yourself. Here is how:

  1. Open your ColdFusion9/stubs/ folder.
  2. Make a call to the webservice using createObject:
    someWs = createObject("webservice", "http://addressToWsdlFile/?wsdl");
  3. Inspect the stubs folder and find the subfolder which is newly created, open it.
  4. There should be a whole subfolder structure which contains eventually some .class files. Copy the root (normaly this is something like a top level domain: com or net or such)
  5. Paste the folder structure to folder which is noted as a class path folder, or make a new folder and put this in the ColdFusion administrator (Server Settings > Java and JVM > ColdFusion Class Path) or in your server.cfc class path settings
  6. Restart ColdFusion (do not forget this!)
  7. Now you can create one of the objects needed in the webservice using:
    someObject = createObject("java", "com.test.testapp.testObj);
    (the dot notated path is corresponding with the copied folder structure to the class files)
  8. The objects should have all the getters and setters. (Use writeDump() (or cfdump) to see all the properties of the classes). So use someObject.setSomeValue("xxx"); to populate.
  9. Call the method with the generated object:
    result = someWs.someMethod(someObject);
  10. Done!


Using SSL with ColdFusion howto

Here is a writeup about how to setup ColdFusion 9 to use SSL. I will describe the steps I needed to take to connect to a site that uses https.

1: inspect the site and download the certificate

Go to the site and inspect the certificate. I use Google Chrome, so I clicked on the lock icon next to the address in the adress bar. Then click on the certificate details.
Click on the button "copy to file" to export the certificate. Choose "Base-64 encoded X.509 (.CER) and choose the filename and location.

2: enable SSL in Jrun.xml

Open the Jrun.xml and search for "SSLService". Here you will see a commented section where all the setting about SSL are. Set the port to the right value (443 is the standard port for ssl), set the right location for keyStore and trustStore. My values are "{jrun.rootdir}/lib/security/cacerts" and "{jrun.rootdir}/lib/security/trustStore". Not sure where the jrun.rootdir points to? Look in the ColdFusion Administrator in "system information" > "Java Home".

3: import the certificate

Here you'll have two options: use the gui in the ColdFusion administrator http://certman.riaforge.org/ (which is the easiest), or import the certificate using the JRE keytool.
You have two keystore files: cacerts and trustStore, the cacerts should only contain the root certificates from the Certificate Authorities (CA) and the trustStore should contain the trusted certificates in which you should import the certificate of the server you wish to connect.

If you use the CFadmin plugin, open the KeystoreManager.cfc and set the KeyStorePath if it is not the default setting and the password (the default settings should be fine). In the init function you can change the file of the keystore which you specified in the jrun.xml in step 2.

If you use the keytool file, open a command prompt and go to the bin folder of your CF jre. There you can find the keytool.exe file.
Make a keystore named trustStore (if it does not exist) by generating a server certificate:

keytool -genkey -v -alias cf -dname "cn=localhost" -keystore trustStore -keypass changeit -storepass changeit
Alias (here set to "cf") is the short name for the certificate, trustStore is the name of the keystore (you should use an absolute path to be shure where the keystore file is written to, the keypass and storepass are the passwords to secure the certificate and the keystore (changeit is default, so it's advised to change this, but be shure it is the same as what is set in the jrun.xml file in step 2).
Import the certificate of the remote server to the trustStore:

keytool -import -v -alias savedCertAlias -file savedCert.cer -keystore trustStore
savedCertAlias is the short name of the to be imported certificate, savedCert.cer is the file of the certificate you saved in step 1 (use an absolute path to be sure you will import the right file), strustStore is the file of the keystore you will save the certificate to (use an absolute path). Consider the -trustcacerts option if you want to trust the whole tree.
List the contents of the keystore or truststore:
keytool -list -keystore keystorefile

4: Enable jvm debug output (optional)

This step is optional, but great to see if everything is working. Add the folowing line to the JVM arguments in the CF administrator:
-Xdebug -Djavax.net.debug=all

This will save all sorts of handy debug output to runtime\logs folder coldfusion-out which comes in handy to see how the SSL connection works (or not).

5: Restart ColdFusion

For all the indivdual steps a restart of the ColdFusion instance is needed so this is a good moment to do so. (changed jvm.xml, added keys to keystore, changed jvm arguments).

6: Check the SSL connection

Make a call to the server which you want to connect to:
<cfhttp 
url="https://someSSLEnabledServer/index.php?someargs=1"
charset="utf-8" 
method="post"
port="443"
result="test" >
If you enabled jvm debug output (step 4) you can see the SSL connection results in the -out log file.

7: Debug!

If everything is working, congratulations! Be sure to disable the debugging because one ssl connection can generate a few Kb of logging information in one call.
If the call fails you should get some hints in the log file, do not trust the coldfusion exceptions you get in your browser, they are not detailed enough to see what is going on. Here are some pointers to what might go wrong:

Keystore or trustStore not found: be sure the files exist and the paths are correct in the jvm.xml. Change the paths and/or generate the keyStore

Not all the CA's of the certificate are trusted by the keystore: Open the imported certificate file and check the certification path. Check all the CA's in the certification path and be shure that all the certificates are either in the keystore or the trustStore. If not then import them to the trustStore (repeat the steps 1-3) and/or consider the -trustcacerts option (see keytool manual).

No CA's are in the trustStore: On one CF server I found a keyStore with only three CA records. You can import all the CA's, but it might be easier to see if your JRE has an updated file.

Certificate or one of the CA's are expired: check if all the certificates in the chain are still valid and updated in your keystores.

Note: This description assumes that only one way ssl signing is needed, if the SSL server requires a certificate from the client you should generate a valid certificate and import it in the keystore. The keytool is limited to X509 v1 generation.If you need X509 v3 then you should use openSSL or another capable tool. Use a tool that is capable of importing private keys, the keytool is not capable to do this.

Here are some references I used:
Tool to import certificates: http://certman.riaforge.org/
Jrun Help / Import certificates | Certificate stores | ColdFusion: http://helpx.adobe.com/coldfusion/kb/import-certificates-certificate-stores-coldfusion.html
Debugging SSL/TLS Connections:  http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html
Search for SSL in: "Configuring and administering ColdFusion"