Showing posts with label security. Show all posts
Showing posts with label security. Show all posts

Friday, November 2, 2012

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"


Friday, June 11, 2010

Connecting to sites which use SSL

If you want to connect to a site which uses https you might get a connection error like "peer not authenticated". To solve this problem you need to import the SSL certificate to your ColdFusion Java keystore. There are a few steps to do this depending on your situation.

If you have a keystore which contains the certificate (which was my case) then you need to export this to a certificate file using the keytool application.

Keytool can be found in your ColdFusion root \runtime\jre\bin\keytool.exe

keytool.exe -export -alias aliasOfKey -v -keystore keystoreFile -file myCertificate.crt
If keytool asks for a password and you don't have ony you can try the default password "changeit".
This exports the certificate with the given alias from the given keystore file to a crt file.

If you don't know the alias of the certificate then you can list the contents of the keystore file using:

keytool.exe -list -v -keystore keystoreFile

You can also open the site in a webbrowser and double click on the key icon. This will view the SSL certificate. Click the details tab. In this window you can save the certificate. Choose BASE64 for encoding and save it to a known location.

Next you need to copy the crt file to the security folder in ColdFusion. This is located in: ColdFusion root runtime\jre\lib\security

In this folder is also the cacerts file which is the keystore for ColdFusion.
Now you need to add the crt file to the keystore:

keytool.exe -import -keystore cacerts -alias aliasOfKey -file myCertificate.crt

And you are done!

Monday, May 17, 2010

Connecting to webservices which require login using cookies

U stumbled upon a problem connecting a ColdFusion site to an external application using a webservice. The normal howtos are insufficient because none of them describe connection to a webservice that requires a login AND use multiple requests. Here is a description how it is done for a webservice which has a separate method for the login and the other functions:

Step one: initiating the webservice
Nothing special here:
ws_securityService = createobject('webservice','http://www.somesite.com/someSecurityservice.asmx?WSDL');
ws_someOtherService = createobject('webservice','http://www.somesite.com/someOtherService.asmx?WSDL');

Step two: maintaining the connection
If you visit a website in a browser it will recognize if you did a previous request. If you login on a page it will remember you so you can load your profile page and so on. By default every request by ColdFusion is a new one, nothing from previous request are remembered, that is why you need to tell ColdFusion to do otherwise:
ws_securityService.setMaintainSession(true);
ws_someOtherService.setMaintainSession(true);

Step three: logging in
In this case the authentication is in a few steps: if you initialize the login the method returns a string which you need to to do a login, this is simplified because there is no need to go in depth here.
challenge = ws_securityService.InitializeLogin(serverUserName); //function returns a key required by the login method
loginsucces = ws_securityService.Login(response); //the real login method

Step four: reading the cookies
After a successful login the webservice will set a cookie with a key to see if the user is authenticated. So this is required by all the other webservices.
server_cookies = ws_securityService._getCall().getMessageContext().getProperty("Cookie"); //this returns an array with cookies

Step five: decoding the cookies
Because I use the underlying Java to add the cookies to a request I need to convert this from the typeless ColdFusion to Java.
Because there will be a conversion error you have to explicitly cast the cookie array by the following code:
String = CreateObject("java", "java.lang.String"); //Get a Java cast string
Array = CreateObject("java", "java.lang.reflect.Array"); //Get a Java cast array
Cookies = Array.newInstance(String.getClass(), arrayLen(server_cookies)); //create the cookie array

Now you need to fill this newly created array with the ColdFusion cookie array:
<cfloop from="1" index="i" to="#arrayLen(server_cookies)#">
<cfset #urldecode(server_cookies[i])#")="" array.set(cookies,="" i-1,=""><!--- ColdFusion arrays start at 1, Java (and all the other programming languages) start at 0 --->
</cfloop>


  


Step six: adding the cookies to all your other webservices
ws_someOtherService._setProperty("Cookie", cookies); //this adds the cookie to your webservice call
Before, you already set the MaintainSession to true so with every request to this webservice the cookies will be added.

Step seven: call the other webservices
Actually: you are done, now you can call the other webservice which require authentication.
someResult = ws_someOtherService.doSomething(someArgument);

If you want to call another authenticated webservice you just have to do the folowing things:

  1. create the webservice to a variable (step one)
  2. set maintain connection (step two)
  3. add the cookie to the webservice (step six)


I hope this helps you and save you some frustrating hours.