CF: ColdFusion 10 experimenting with alternate connector with IIS

A more up-to-date article about this can be found here:
https://www.boncode.net/boncode-connector/using-boncode-with-adobe-coldfusion

If you know me, you know I really don’t like the ISAPI connector Apache Tomcat has been using for ages to allow for connectivity between Apache Tomcat and IIS. This annoyed me sooo much I went to create an alternative with the BonCode connector.

When Adobe released ColdFusion 10, however, they built their connection mechanism on top of the original ISAPI connector for IIS. In addition, they made modifications to both the Tomcat server code and the ISAPI connector code to accommodate their particular needs.

The upside of this is things continue to mostly work like they have in the previous iterations, with maybe the only exception being, that you can no longer use CFFLUSH with the out of the box setup. You actually have to disable connector buffering (this has other side effects that you maybe OK with maybe not). To do so go to {CF-Home}/config/wscoonfig/{connector-no}/isapi_redirect.properties. Change iis_buffer_enable to false and restart the IIS.

By now you also know that Adobe does not recommend you use the default Tomcat instance to host anything else besides ColdFusion. A good blog post: “What’s the deal with Tomcat in ColdFusion 10?”  by Rupesh Kumar explains this in more detail.

On the other side, if you want to easily use one IIS to front-end multiple tomcat instances or applications, you really have to do something about the non-standard connector that ships with CF10. Your IIS gies otherwise completely monkey-crazy if you try to work with the Adobe supplied one.

Thus, time for a good experiment. I built in experimental support for the Adobe specific idiosyncrasies to the AJP protocol into the BonCode connector with version 1.0.2 and was curious whether I could get this to work with the release version of CF10.

The first step is actually to install CF10 as usual. Once the server install of CF10 is complete, however, you will need to remove the existing connector via the webserver config tool like so:

Once the removal of the Adobe connector is done, you can download the BonCode connector from RiaForge connector and start the standard install.

Accept all the defaults but once you get to the Tomcat information page, you will need to change the port to 8012 since this is the port CF10 will accept connections under for AJP, like so:

That’s all folks. Now you can configure additional sites, and tomcat instances as outlined in the connector manual and your IIS server will happily serve you.

If you want to take this a little further  I would suggest a few tweaks:
a) If you want CFFLUSH support, check the appropriate option during the install of the connector on the options page.This is truly implemented as HTTP flush detection, rather than disabling of buffers and will not cause extra client or network overhead.
b) If you want the CGI.PATH_INFO variable to be populated exactly like CF10, you will need to change the connector setting file slightly. First, find out where the setting file is located by calling this URL on the server:
 http://localhost/a.cfm?BonCodeConnectorVersion=true
Then, add the PathInfoHeader directive like so to the setting file:

<PathInfoHeader>path-info</PathInfoHeader>

c) If you want to use the same packet size that Adobe defaults to, you can also change the packet size using the PacketSize directive in the setting file like so:

<PacketSize>65531</PacketSize>

This reduces the number of packets exchanged between IIS and CF Tomcat but uses a larger buffer block.

d) If you want to explore the full functionality of CF10 I would also recommend that you add the wildcard mappings to the appropriate sub-folders in your  CF10 site. This is used for some of its flex and background features:

/CFFormGateway
/flex2gateway
/CFFileServlet
/cfform-internal
/flashservices/gateway
/flex-internal
/rest

The directions on how to add wilcard mappings are also in the manual that is included in the download package for the BonCode connector.

Happy experimenting.

B.

UPDATE ! UPDATE ! UPDATE ! UPDATE! — 8/1/2012

I added a setting specifically to address the behavior of the connector for Adobe backends with version 1.0.8 of the connector. This allows the connector to be changed with only one switch and everything should fall into place:

<EnableAdobeMode>True</EnableAdobeMode>

UPDATES: — 5/30/2013

Adobe made changes that are only reflected in version 1.0.15 of Boncode. If you are using any earlier version you will need to change the server.xml file normally located here:

cf_root/runtime/conf/server.xml

Find line similar to:
<Connector port=”8012″ protocol=”AJP/1.3″ redirectPort=”8443 packetSize=”65531″/>


And add the packetSize directive. This is not needed if you use version 1.0.15 or higher of connector.

UPDATES — 01/10/2014

More time spent going through the grunge work of analysis when people reported issues more changes discovered.  For example, the Adobe connector hard-codes but hides the packetSize attribute in tomcat. Adobe is actually using 65531 bytes as packet size now. Why? No one knows.
Version 1.0.18 (to be released shortly) of the connector makes this adjustment automatically when you turn on Adobe mode so you don’t get odd pages with bytes missing. This is pretty mean. I made changes accordingly to above examples.
If you use standard Tomcat, but switch to Adobe mode, you will need to put this value into the Tomcat server.xml configuration file from now on.

UPDATES — 02/17/2014

Some hard core testing has gone into release 1.0.18g of the connector and as a result of feedback from the community I have removed the “experimental” moniker for CF10. Will support you all the way now ;o)

UPDATES — 10/18/2014

Please note that there are some changes to the default port used for Adobe ColdFusion 11. ColdFusion 11 uses port 8014 for AJP traffic.

As usual, feedback is appreciated. Please post on the Riaforge.org site.

CF: Installing ColdFusion 10 with IIS

I thought I write a quick note on the installation of CF10 on Windows, especially if you want to use IIS7.
Let’s say you installed IIS with the most basic setup and the tried to install CF10.

During the setup of CF10 you will be prompted at the web server selection and configuration step to install more Role Services for IIS like this:

You would correctly interpret this to mean:
Install: ASP.NET, ISAPI Extensions and ISAPI Filter like so:

However, this is not quite accurate. Since you still will not be able to proceed.You will also need to add the CGI Role Service.

Best,
B.

CF: breaking queries into pages of data

Another day another problem to solve. With many more Ajax type screens, managing the data flow to the front-end needs to be baked into the core system. Otherwise, it seems, the users really do not have a care in the world about how much data they consume….
In my specific case, I am receiving a query (structured data in records), any type of query from any type of DB. I do not know the number of columns, indexes, pks or anything. The job is to be able to return a page of records from this query without going back to the database (would be hard since we don’t know the database either). This could even be a QofQ, i.e. code generated, set of records.
I scratched my head several times over this, but still do not think I have an elegant solution. Nonetheless, I have a working one.
I wanted to avoid looping over the query itself and creating a new one record by record. I decided to use a Query of Query approach though only when needed. To do that I dynamically attach another column to the original query that I am using as primary key. Then, I am calculating the start and end records for the page and using a QoQ to just return the ones requested for the Page.

<cffunction name="getQueryPage" access="public" returntype="query" hint="return a query with subset of records based on page argument.">

 <cfargument name="selRecords" required="Yes" type="query" hint="the base query with records">

 <cfargument name="Page" required="no" type="numeric" default="1" hint="which page (chunk) to return">

 <cfargument name="PageSize" type="numeric" default="50" hint="size of record chunk. this is also the max number of records to be returned.">



 <cfscript>

  //init stuff

  var dataQuery = arguments.selRecords; //realias

  var selReturn = dataQuery;

  var iPageCount = ceiling(dataQuery.recordCount/arguments.PageSize);

  var lstCols = dataQuery.ColumnList; // capture col list before change 

  var blnDoSubQuery = false;

  var intStartRec = 0;

  var intEndRec = arguments.PageSize;

  var zzArray = ArrayNew(1); 

   

  

  arguments.Page = int(Abs(arguments.Page)); //ensure that we have no negatives

  //if we request a page that is too big return last page

  if( arguments.Page GT iPageCount) arguments.Page = iPageCount;

  

  //attach control column to base data if calculations require it and or it is not present. 

  if (ListFindNoCase(lstCols,"zzzPageControlCol") IS 0 AND arguments.Page GT 0) {

   intStartRec = 1 + ((arguments.Page -1) * arguments.PageSize);

   intEndRec = intStartRec + (arguments.PageSize -1);   

   //only if the overall query has more records than requested do we need to do anything.

   if ( NOT (intStartRec IS 1 AND intEndRec GTE dataQuery.recordCount)) {

    blnDoSubQuery = true;

    //attach control col

    zzArray = ArrayNew(1);   

    //if we do not think that the passed in query is cached, we can probably use a scheme

    //were we only mark the records that we need to return.

    //however, marking all records one time is faster, if the base query is cached and repeatedly pages

    //need to be returned

    for (i=1; i LTE dataQuery.Recordcount; i++) {

     zzArray[i] = i;

    } 

    QueryAddColumn(dataQuery,"zzzPageControlCol","Integer",zzArray);      

   }; 

  }

 </cfscript>

 <!--- only do subquery if needed, ideally the base query is cached somehow but that is beyond this scope (bsoylu) --->

 <cfif blnDoSubQuery>

  <cfquery name="selReturn" dbtype="query" >

   SELECT #lstCols#

   FROM dataQuery

   WHERE zzzPageControlCol >= #intStartRec# AND zzzPageControlCol <= #intEndRec#

  </cfquery>

 </cfif>

 

 <cfreturn selReturn>

</cffunction>

Cheers,
B.

CF: When does OnRequestEnd get executed

This is one is from my main man Kip (@kipthegreat) he ran through this exercise using Adoce CF 9.
Might be helpful for others to know.

Situation
Does OnRequestEnd() get
executed?
Page calls <cfabort> tag
Yes
Page calls to redirect
user
Yes
Page calls with
abort=”true”
Yes
Request exceeds timeout
NO
Uncaught exception
NO

The lesson to pay attention to is to catch and handle your exceptions ;o)

 Cheers,
-B

CF: New version of BonCode PGP library released

I had a few request to look into the PGP library I released for ColdFusion and Railo last year. It took me a while to understand my own code, then, a while longer to implement the features that I wanted to add ;o)

The main add on this time is the ability to create single pass signed files. This allows you to create a file where you are assured that only the authorized receiver can read them, while the receiver is assured that the sender is authentic as well.  Yep, I know sound like cold-war stuff, but it is quite common scenario in financial exchanges to assure both sides that everything is the way it should be.

To a lesser level some other additions and bug fixes were completed as well.
All this, as usual is open source.

You can download code, examples, and implementation from here:

https://github.com/Bilal-S/cfpgp/releases/tag/2.0.0

Best,
B.

CF: Setting up the OWASP ESAPI Library for use with ColdFusion and Railo

If you are taking application security seriously or have been curious about it you know by now that the native tools built into ColdFusion and Railo are not sufficient to hinder the serious hacker from making headway.

To truly use best practices you can do a lot of code development, or, fall back to a project that has already proven its merit through many years of practical use.

I am referring to the OWASP Enterprise Security API (ESAPI). Unfortunately, getting this puppy running in any shape requires some reading muscle and some luck and some powers of deduction.

I am summarizing here the findings, so you don’t have to run through the maze of options and boiling it down to something simple.

First, you will have to download the jar file (as of this writing it would be esapi-2.0.1). The download is around 14MB but you only need the esapi-2.0.1.jar file. Copy the jar file to (backup any esapi file that already exists in there first):
[cfroot]/wwwroot/WEB-INF/lib in Adobe Coldfusion.
WEB-INF/lib in Railo

Then, download a good ESAPI.properties file. Most of my head banging and hair ripping surrounds finding the property definitions. Can’t stress this enough. Start with the one from source code it has good comments. Go through this file carefully and make needed changes. Make sure all directories referenced in the properties file actually exist on your drive system and also change default Encryptor.MasterKey and Encryptor.MasterSalt to something you are comfortable with, e.g. do not use something like this:

Encryptor.MasterKey=changeme
Encryptor.MasterSalt=blah

After you made changes save it (e.g. c:\esapi\files).

Thirdly, make environment start up changes.
If you are using Adobe Coldfusion you will need to change the JVM startup properties in CF Administrator to add a property and point to place where you placed ESAPI.properties file. E.g.:
-D org.owasp.esapi.resources=c:\esapi\files

For Railo, the above is done in Tomcat/Jetty startup parameters.

Fourthly, change classpath (Yep, you heard right change JAVA classpath): Add the directory you placed the properties file in to Java classpath. This is something that had me stumped as well.

After all of the above, give your server a good schake (restart), and then test whether all works.
Simple code snippet:

<cfset esapi = CreateObject("java","org.owasp.esapi.ESAPI")>

<cfset encoder = esapi.encoder()>

<cfoutput>

 <cfset myInput="<script>some input for html context; 

  alert('doing something you don't want');</script>">

  #now()# <br/>

  #encoder.encodeForHTML(JavaCast("string", myInput))#

</cfoutput>

The good news is that Adobe is looking into bundling this in the future so you don’t have to. However, in the meantime this is good practice ;o)

Best,
B.

CF: Tracing AMF (Action Message Format) packages for Flex/BlazeDS in Coldfusion

I know I had seen this and done this before but for some reason I could not find it. I am looking at a Flex based component that makes remote calls to ColdFusion (Flash Remoting), then, renders some of the data. Now I wanted to find out what is happening and more specifically what data is being exchanged between Flex and ColdFusion.
As you might know, the exchange between CF and Flex is in AMF format, which is a binary format and thus not easily readable over protocol sniffer.
I know, I know, I can get many tools, and ServiceCapture is mentioned many times; but I wanted to do this simpler.
What I done in the past is used the command window to get this, but with many things, you forget, or just get older ;o)
So you can start ColdFusion in a Command / Terminal window, by going to the installation folder and finding the right startup script.
For windows:
[cfroot]\bin\cfstart.bat

This will start the ColdFusion server in command window:

Command Window running ColdFusion

However, this did not automatically decode the AMF messages or gave me insight into flash remoting. In order to that I had to find the flex services-config file. On stand-alone server install on Windows this would be located here:
[cfroot]\wwwroot\WEB-INF\flex\services-config.xml

find the logging section and change logging level to “Debug” like so:

<logging>

        <target class="flex.messaging.log.ConsoleTarget" level="Debug">

        ...

</logging>



You can even change the prefix of the messages, e.g. to Flex like so:



<logging>

        <target class="flex.messaging.log.ConsoleTarget" level="Debug">

            <properties>

                <prefix>[Flex] </prefix>

This is the cheap way of getting debugging going on the protocol and see what is being exchanged.
Hope this helps,

-B

CF: CFCamp 2011 presentation and sample code

A long day at CFCamp came to a social conclusion at the Marriott-bar. This again confirms the impression that the ColdFusion community is approachable by old and new hands alike.

Another interesting fact about the CF community emerged. According to the custodial support staff, the CFCamp attendees consumed three times as much coffee as crowds of a similar size. Definitively a mark of distinction.

Thanks to the organizers, presenters, and attendees for making this a solid CF event.
Overall, learned new things from all and had a Pretzel to boot.
As discussed, I posted the the presentation slides and sample code for download.

Cheers,
B.

CF: Munich in the Fall, CFCamp 2011

So, you just missed Oktoberfest and were wondering what else there is to do in Munich in the Fall. Well, you happen to be in luck, especially if you are a ColdFusion enthusiast.
It so happens that this year a few fellow believers in the art of the Pretzel and motivated ColdFusion learners are assembling on October 28th for CFCamp 2011.

Even yours truly will make the trek down  to Bavaria’s Capital to chat and learn from others. Will also do a talk on application security, sharing some nuggets of the school of hard knocks etc.

As far as I understand it, it is not too late to signup and the Beer and Pretzels are beckoning….

Cheers,
B

CF: Using URLEncoder to secure URL Parameter against CSRF and XSS

In my presentation about ColdFusion Application Security I also showed a reference implementation of an URLEncoder that can assist with three scenarios:

Cross Site Scripting: If scripts are injected through URL parameters, this encoder will ensure that no user inputs besides the one set by CF are accepted.

Insecure Direct Object Reference: By encrypting the object references in passed URL the object reference are no longer exposed to users and cannot be changed by users.

Cross Site Request Forgery: By adding additional reference in the encrypted packages the URLEncoder will assist with Cross Site Request forgery attempts.

The URLEncoder allows a very flexible way of transporting data via URL parameters in a secure fashion. It is not restricted to primitive/simple data types. Complex data such as arrays and structures can easily passed  via the URL using this component as well.

Moreover, additional security option are available. During encoding, you can specify whether the generated URL has an expiration and or can only be used from the originating URL.

During the decoding phase the URLEncoder you can specify which scope the transported data from the URL parameters will be placed in. By default this will be placed into Request.URL, however, you can change this to be placed into the regular URL scope so that legacy application will only need minimal change to add this layer of security.

Here is the link to the download to the project from RIA Forge.

Cheers,
-B.