The Solution to Flex Remoting Over SSL

If you've tried calling ColdFusion CFCs with RemoteObject over SSL in your Flex apps, you probably feel my pain already, because you have either tried to get it working and gave up, or had a heck of a time getting it working. Adobe's documentation for this specific need wasn't helpful to me, and discussion about it online is relatively sparse and unsure as well, from what I've seen. My intranet environment at work demanded that I get remote communication with CFCs working over SSL, so as I neared completion of my first couple Flex apps, I needed to get an understanding of this issue. Hopefully it will be useful to others.

So, what's the problem? In a nutshell, when you try to use the RemoteObject component in a Flex app to communicate with CFCs, the default installation of ColdFusion 8 and Flex Builder 3 will compile your app to communicate with the ColdFusion server over HTTP (http://yourserver.com/flex2gateway/), not over HTTPS (https://yourserver.com/flex2gateway/cfamfsecure), regardless of whether the SWF was loaded over HTTPS or not.

If your site exists in both HTTP and HTTPS, you may not even be aware this is happening. I wasn't aware of it while I was developing on my local machine. But our production server hosts its site only in HTTPS and the site on port 80 is a nearly empty site that redirects all requests to the SSL-protected version of the site. So this behavior broke my Flex app.

If your site exists only in SSL or sensitive data is being transmitted to and from the Flex app and the CFCs, you probably are trying to get RemoteObject to communicate over SSL.

Quick workarounds. If you have time and leniency to skirt the issue, you can avoid the RemoteObject/SSL issue. You can always use the HTTPService and WebService components instead of RemoteObject. But like most workarounds, this has its disadvantages and limits you from the benefit of using RemoteObject.

I imagine you also could set up a ColdFusion mapping to make the CFCs available on the HTTP site, but this solution is viable only if you really don't care about security, in which case you probably wouldn't have your site wrapped in SSL anyway.

The solution. What makes the solution tricky is that there are a few things that have to be configured properly, and there are some pitfalls along the way that can be misleading. The primary solution lies in some changes to the ColdFusion server's config files services-config.xml and remoting-config.xml. These both reside in {ColdFusion installation}\wwwroot\WEB-INF\flex\. For instance, on my Windows workstation, this is located at c:\ColdFusion8\wwwroot\WEB-INF\flex\.

1. Add the secure channel to remoting-config.xml. ColdFusion 8 already has a channel in its configuration for RemoteObject over SSL--it is called "my-cfamf-secure"--it just isn't configured to be used. So you have to add the "my-cfamf-secure" channel to remoting-config.xml. To do this, add <channel ref="my-cfamf-secure" /> to the <default-channels> node and the <channels> node for the "ColdFusion" destination.

In other words, your new remoting-config.xml file should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
    <adapters>
        <adapter-definition id="cf-object" class="coldfusion.flash.messaging.ColdFusionAdapter" default="true"/>
        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter"/>
    </adapters>
    <default-channels>
        <channel ref="my-cfamf-secure"/>
        <channel ref="my-cfamf"/>
    </default-channels>
    <destination id="ColdFusion">
        <channels>
            <channel ref="my-cfamf-secure"/>
            <channel ref="my-cfamf"/>
        </channels>
        <properties>
            <source>*</source>
            <!-- define the resolution rules and access level of the cfc being invoked -->
            <access>
                <!-- Use the ColdFusion mappings to find CFCs, by default only CFC files under your webroot can be found. -->
                <use-mappings>false</use-mappings>
                <!-- allow "public and remote" or just "remote" methods to be invoked -->
                <method-access-level>remote</method-access-level>
            </access>
            <property-case>
                <!-- cfc property names -->
                <force-cfc-lowercase>false</force-cfc-lowercase>
                <!-- Query column names -->
                <force-query-lowercase>false</force-query-lowercase>
                <!-- struct keys -->
                <force-struct-lowercase>false</force-struct-lowercase>
            </property-case>
        </properties>
    </destination>
</service>

This brings me to the first pitfall to watch out for. Be sure to list <channel ref="my-cfamf-secure" /> ahead of <channel ref="my-cfamf" /> so that ColdFusion will try the secure channel first.

2. Add a property to make IE happy. At this point, your configuration will be adequate for Firefox. However, IE still seems to get tripped up and tries to access the insecure channel. To fix this, just add <add-no-cache-headers>false</add-no-cache-headers> to the <properties> node of the <channel-definition> nodes for "my-cfamf" and "my-cfamf-secure" in services-config.xml.

I won't display the entire services-config.xml file here, but your "my-cfamf" channel definition will now look like this:

<channel-definition id="my-cfamf" class="mx.messaging.channels.AMFChannel">
    <endpoint uri="http://{server.name}:{server.port}{context.root}/flex2gateway/" class="flex.messaging.endpoints.AMFEndpoint"/>
    <properties>
        <polling-enabled>false</polling-enabled>
        <serialization>
            <instantiate-types>false</instantiate-types>
        </serialization>
        <add-no-cache-headers>false</add-no-cache-headers>
    </properties>
</channel-definition>

And the "my-cfamf-secure" channel definition:

<channel-definition id="my-cfamf-secure" class="mx.messaging.channels.SecureAMFChannel">
    <endpoint uri="https://{server.name}:{server.port}{context.root}/flex2gateway/cfamfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
    <properties>
        <polling-enabled>false</polling-enabled>
        <serialization>
            <instantiate-types>false</instantiate-types>
        </serialization>
        <add-no-cache-headers>false</add-no-cache-headers>
    </properties>
</channel-definition>

Some more pitfalls to consider. These can be really misleading, making you think your changes aren't working.

A. Flex Builder incorporates these settings into your app when it compiles the SWF. Go to your Flex project's properties, under "Flex Compiler", and you'll see a reference to your services-config.xml file. If your SWF is compiled on a workstation that hasn't had these changes, it will not work on your server, even if you did change your server's config files. So be sure that your local installation of ColdFusion has its services-config.xml and remoting-config.xml files updated just like your production server.

B. On a related note, be sure to recompile an app if you've compiled it before making these config changes. You can recompile in Flex Builder by going to Project > Clean. That option will ensure that you have a clean, recompiled SWF.

C. If your SWF file is actually served on port 80, it will not be allowed to communicate over the secure channel unless you tell it that it is permissible to do so by setting up a crossdomain.xml file. Check out Shannon Whitley's post SSL, crossing domains, and Flex to read a bit on that.

Tools for the job. With the right tools, you can test all of these things out on your own. For instance, Firebug and Fiddler are great tools for Firefox and IE respectively that clearly show your Flex app's behavior, and whether it is attempting to access the secure or insecure channel. They also show the app attempting to access a crossdomain.xml file when the SWF file was loading over HTTP, because it's first attempt is to make a cross-domain connection to the secure HTTPS channel.

The great thing about this configuration is that your SWFs will use the secure channel when they can, but silently fail over to the insecure channel. So your development workstation doesn't have to use SSL, but your compiled apps will utilize it when you move them to your production server. This is cleaner than setting up a separate "Destination" in remoting-config.xml, or other solutions that require changes to your app's code. Alas, I am still green in the Flex universe and don't claim anything different. Nevertheless, this solution is working perfectly for me and I hope it proves useful for you.

5 Responses to “The Solution to Flex Remoting Over SSL”

  1. hsTed Says:

    I have fought issues with RemoteObject config on our prod server until becoming disgusted and finding another way. Your post inspired me to at least try your recommendations and I did so today to no avail. I’m absolutely convinced there’s something screwed up on that box, and I don’t have the necessary permissions to adequately diagnose or repair.
    Just wanted to say thanks for posting — I’m sure it will help others.

  2. Josh Says:

    @hsTed: I am really bummed to hear that. If you want, send me your info/configs and I’d be happy to offer a second opinion.. FWIW..

  3. Romain Says:

    Thanks a lot!
    The trick is also working for a BlazeDS/Tomcat backend.

  4. Adam Says:

    We have an odd thing (actually more than odd down right frustrating) happening in our production environment. In our test environment, we can use both SSL and non SSL remote objects connections without any issues. However, our production environment won’t return objects from remote objects calls over SSL which are greater than 2k or so. Our non-ssl calls in production work just fine, and calls which only return small data are fine. The major difference with our production enviroment ssl setup and our test ssl setup is our production servers our load balanced were the SSL occurs on the load balancer, so the CF8 server/Jrun server actually sees non-ssl calls. The gateway logs show the correct data being sent in a message.

    Anyone experienced anything similar in load balanced ssl environments?

  5. Cameron Says:

    Thanks! This method works great! Thanks for the the information. I was beginning to pull my hair out with the standard “Send Failed” error message. And I was dreading using one of the other methods which attempts to create a “code based” solution.

Leave a Reply

  Theme Brought to you by Directory Journal and Elegant Directory.