Flex2 (and 3) RemoteObjects over SSL with ColdFusion

I just deployed a Flex app to an SSL secured host, and ran into some issues getting AMF over SSL working.  Googling turned up the answers, but in rather fragmented form.  So I'm coalescing them here.  In a nutshell, you have to create a new channel (my-secure-amf) that uses the secured versions of the AMF classes (both AS and Java), and then register it as a usable channel for the ColdFusion destination.  Here's a diff from my services-config.xml (in /WEB-INF/flex) with the four important bits bolded:

--- services-config.xml 2007-09-01 00:37:25.000000000 -0700
+++ services-config.xml 2007-09-01 00:59:41.000000000 -0700
@@ -13,6 +13,7 @@
             <destination id="ColdFusion">
                 <channels>
                     <channel ref="my-cfamf"/>
+                    <channel ref="my-secure-cfamf"/>
                 </channels>
                 <properties>
                     <source>*</source>
@@ -48,6 +49,15 @@
                 </serialization>
             </properties>
         </channel-definition>
+        <channel-definition id="my-secure-cfamf" class="mx.messaging.channels.SecureAMFChannel">
+            <endpoint uri="https://{server.name}:{server.port}{context.root}/flex2gateway/" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
+            <properties>
+                <polling-enabled>false</polling-enabled>
+                <serialization>
+                    <instantiate-types>false</instantiate-types>
+                </serialization>
+            </properties>
+        </channel-definition>
     </channels>

     <logging>

In addition to this server-side config, you need to ensure your client connects to the proper channel and with the proper Channel (the AS class) implementation.  If you're using services-config.xml in your compilation process, it's a no brainer, but if you're manually configuring your ChannelSet in code (parameterized, of course), you have to watch out.  If you want to do the latter, here's how I do it:

private function configRemoteObject(gateway:String, cfc:String, useSsl:Boolean):RemoteObject {
  var cs:ChannelSet = new ChannelSet();
  if (useSsl) {
    cs.addChannel(new SecureAMFChannel("my-secure-cfamf", gateway));
  } else {
    cs.addChannel(new AMFChannel("my-cfamf", gateway));
  }
  var ro:RemoteObject = new RemoteObject();
  ro.destination = "ColdFusion";
  ro.channelSet = cs;
  ro.source = cfc;
  ro.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
    if (event.token.hasOwnProperty("resultHandler")) {
      event.token.resultHandler(event);
    } else {
      trace("result event with no resultHandler: " + event);
    }
  });
  ro.addEventListener(FaultEvent.FAULT, function(event:FaultEvent):void {
    if (event.token.hasOwnProperty("faultHandler")) {
      event.token.faultHandler(event);
    } else {
      trace("FaultEvent: " + event.fault.message);
    }
  });
  return ro;
}

The three arguments to the method are pulled in via a URLLoader to an XML file such as the one below that is part of the deployment configuration (i.e. not part of the codebase).

<?xml version="1.0" encoding="utf-8"?>
<settings>
  <gateway>/flex2gateway/</gateway>
  <useSsl>false</useSsl>
  <cfc>sorter.cfcs.count_facade</cfc>
</settings>

I don't claim that this is the best way, but it does let you easily change where your SWF connects to without recompilation, which therefore lets you build your Flex projects standalone (no compile-time server linkage).  Quite useful if you have a variety of environments you want a single project/SWF to work in.

11 responses to “Flex2 (and 3) RemoteObjects over SSL with ColdFusion”

  1. John Clarkson

    Thanks, really helpful post. As you noted, information on using secure AMF is very fragmented. I am still not clear what the expected bahaviour is when you specify a ChannelSet with two or more channels – either in Flex or in the WEB-INF/flex/remoting-config file like this:

    <default-channels>
    <channel ref="my-cfamf-secure"/>
    </default-channels>

    <destination id="ColdFusion">
    <channels>
    <channel ref="my-cfamf-secure"/>
    <channel ref="my-cfamf"/>
    </channels>
    <properties>
    <source>*</source>

    The implication (supported by the ChannelSet description in the Flex Documentation) is that I can specify a secure channel as the default and if it is not available then the non-secure channel will be used? When I get a chance I'll do some tracing to see if this is the case, as it would provide an easy mechanism for moving between secure and non-secure deployment environments.

  2. John Clarkson

    An update of my investigations – I have deployed my CF-Flex application on both local host (http) and also on a remote host with SSL certificate installed. I have built the Flex application using the remoting-config.xml settings as per my previous post and have now been using SmartSniff to look at the packets between my Browser and the Server to see which channel is actually being used. I should make it clear that I am not specifying the channelSet in my client as Barney does in his original post – I am just specifying it in the remoting-config file when I build the application with the default as my-amf-secure – if I trace remoteObject.channelSet I see that it does include both my-amf and my-amf-secure.

    In conclusion, with the same application deployed (using IE7):
    - as expected http packets are sent and received with the http localhost deployment.
    - https packets are sent from Flex to CF but the responses are http packets with the SSL deployment!

    Using Firefox I found I needed to specify the my-amf channel before the my-amf-secure channel within the channels tags in order to get the same behaviour as observed with IE! With the channels specified in the opposite order the http packets are returned to the Browser.

    So I have got something wrong somewhere! More investigations required.

  3. John Clarkson

    The second to last sentence regarding Firefox in my previous post should have said: "With the channels specified in the opposite order the http packets are NOT returned to the Browser."
    I do have add-no-cache-headers set to false in service-config.

  4. rajesh

    Hi Barney,

    You said

    "In addition to this server-side config, you need to ensure your client connects to the proper channel and with the proper Channel (the AS class) implementation. If you're using services-config.xml in your compilation process, it's a no brainer,"

    but, i dont know how should i do it if i am using the services-config.xml in compilation process. Can you please let me know what to do in this case ?

  5. Greg

    Is there any update to this discussion?
    our setup:
    - Flex Builder without -services tag (Basic setup – no server)
    - Wrapper grabbing URL and adding "/flex2gateway/" and passing string in via flashVars.
    - flashVars read and set to variable in Flex application
    - variable used as endpoint in RemoteObject (endpoint="variable")
    - path to CFC set in RemoteObject source (source="path.to.cfc")
    - services-config.xml has default channel ()and new secure channel ()
    - non secure (endpoint uri="http://{server.name}:{server.port}/flex2gateway/" class="flex.messaging.endpoints.AMFEndpoint"/>)
    - secure (uri="https://{server.name}:{server.port}/flex2gateway/" class="flex.messaging.endpoints.SecureAMFEndpoint")
    - context root removed as we do not have one set

    Should I be setting up a connection manually instead and setting my channels there?
    If I do this manually, don't I then limit my returns to XML only and don't I kill any possiblility of pushing (messaging) my data from the server to the client for realtime data?
    Shouldn't my secure endpoint in the config-services.xml be "/flex2gateway/cfamfsecure"?

  6. Greg

    I should add that everything is working correctly however the data is NOT encripted via the secure channel from Flex. Is anyone working on this from Adobe?

  7. Balashankar

    I followed the steps you have given, but still this error comes?

    (mx.messaging.messages::ErrorMessage)#0
    body = (null)
    clientId = “EBEBD2B1-1B0D-4FBA-96D7-E4EF997B458E”
    correlationId = “B5BB5A82-F351-0C08-F627-08FA97B7E72B”
    destination = “ColdFusion”
    extendedData = (null)
    faultCode = “Server.Processing”
    faultDetail = (null)
    faultString = “Destination ‘ColdFusion’ not accessible over channel ‘my-cfamf-secure’.”
    headers = (Object)#1
    messageId = “EBEBD2B1-1B1E-01EC-285E-843B7C436FEB”
    rootCause = (null)
    timestamp = 1331590502987
    timeToLive = 0
    

    If I use ‘my-cfamf-secure’ as first line of code in &ltchannnels&gt tag, the same above error is displayed, if I use, ‘my-cfamf' as first line of code in &ltchannels&gt tag, faultString="Connect disconnected before an acknowledgement" is the error displayed.

    What else can I do to make my CF9 server to work?

    One more point, the same set of files works fine in CF8 server box without any issue.

    Please give some tips.