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.
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.
John,
My understanding is that a given destination can have an arbitrary number of channels associated with it, since you specify both the destination to connect to and the channel to use in your Flex app. I don't know that I've ever actually tried doing both at the same time, however.
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.
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.
Interesting, John. At work, we're going to be deploying our first Flex-based e-com app in a couple weeks, and obviously be using SSL for it. To this point, we haven't seen any issues, but we're using the in-Flex channel config stuff, not using services-config.
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 ?
Rajesh,
I honestly don't know. I believe if you only have a single channel in your destination config, it'll use it. I've never actually compiled a SWF with services-config.xml, I've always managed my channelsets manually for the flexibility. The Flex docs should turn up the answers. My point was that if you use services-config.xml, the compiler is in charge of picking the right classes to use, instead of having to do it manually.
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"?
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?
I followed the steps you have given, but still this error comes?
If I use ‘my-cfamf-secure’ as first line of code in <channnels> tag, the same above error is displayed, if I use, ‘my-cfamf' as first line of code in <channels> 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.
Balashankar, I'm not sure what to tell you. I haven't used Flex for anything in probably four years, which means I've never done anything with Flex and CF9 together. You might check the LCDS support forums on Adobe.com, if there is such a thing.