Today I was working on a Flex application which uses a lot of Remoting calls to a bunch of ColdFusion CFC methods. I wondered what the most efficient way of securing these methods would be since they are effectively wide open to the world as they all (have to) specify access="remote". This means that anyone with a web browser can invoke the methods and they will even return nice error messages when certain parameters are missing.
One way of restricting access would be to run all Remoting calls through an intermediate page or CFC which handles authentication and access control and which in turn invokes the (now private) CFC methods. I found this a bit cumbersome and I also knew that there was a better way - I remembered the setCredentials method back from the AS2 days. You can see this described in greater detail by Brandon Purcell in his MAX session Securing Applications from 2003(!), but unfortunately it is not directly usable in today's Flex world.
While Brandon's example is great, and Ray Camden also has some details to add, neither example had all the pieces I needed, particularly an example of not just authenticating a Flex application properly with a CFC but also how to log out again (and to jump ahead, simply running a cflogout tag did not work...).
I ended up using a combination of what Ray did, plus roughly the logic Brandon deployed, and added a Flex example to show (like Ray) how to call a secured and an unsecured CFC method. In addtion I added a separate, explicit call to Flex's setRemoteCredentials() on the RemoteObject class in order to trigger the cflogin logic in ColdFusion's Application.cfc.
Unfortunately I cannot show you a working example, but I am providing the sources for the Flash Builder project and CF files. Note that my example is set up to run on localhost, and I also specified a compiler flag of -locale en_US -services "services-config.xml" in Flash Builder. My services-config file is also included.
Here's how I structured my example:
1) Application.cfc: this file contains an onRequestStart which gets invoked on every request to this application, including cfm pages as well as cfcs. It contains a cflogin tag which executes only if the user making the request has *not* yet been authenticated. Inside the cflogin tag is a cfif tag which logs the current user in as long as the necessary credentials are passed in - this happens by using setRemoteCredentials() on RemoteObject in Flex/ActionScript.
<cfset This.name = "FlexCredentials">
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cfif isDefined("cflogin.name") and isDefined("cflogin.password")>
<!--- normally you would add authentication logic here, verify the username and password before running the next line - I do it the simple way --->
<cfif cflogin.name eq "stefan">
<cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="Client">
2) MyComponent.cfc: This file contains all the remote methods we call from Flex. One method (called 'normalMethod') can be called by any user (unauthenticated), another can only be called once logged in, and a third is used to log out (more details on that below).
Access control is provided by using the CFC's built-in roles attribute. An authenticated user is assigned a role of 'Client' and the 'secureMethod' in the CFC is locked down by specifying that role.
<cffunction name="normalMethod" access="remote" returntype="String">
<cfreturn "Unsecured CFC method called successfully.">
<cffunction name="secureMethod" access="remote" roles="Client">
<cfset response = "Success. Secure method called by " & getAuthUser()>
<cffunction name="logoutMethod" access="remote">
<cfset response="Logged Out Succesfully">
3) The Flex Application: this is slightly more complex than it needed to be for the purposes of this example, but hopefully it's not too confusing. Rather than trying to explain the classes in detail please feel free to post any questions you may have in the comments below.
Log Out Issues
In detail, what I was seeing was that I could still invoke the secure method from Flex after I had run the CFC's logout method and included cflogout tag. Switching directly to the browser - keeping the Flex app open in another tab - did NOT allow me to invoke the secure CFC method, so from that angle the cflogout tag appeared to had done its job.
To really 'kill' the user's session inside the Flex app itself I had to explicitly call setRemoteCredentials again from Flex passing invalid login credentials. I have a theory on what is happening: the logout method does do its job as described and the user is actually logged out, but only until he tries to invoke another CFC method via the Flex app. As soon as that happens, Flex will re-send the previously set credentials (username, password) and re-authenticate the user using the cflogin tag in Application.cfc. This can apparently be confirmed by invoking the CFC method directly using a web browser both after the logout method has been called and then again after another CFC method has been invoked via Flex. Calling it via the browser after invoking logout in Flex results in a failed request, but after the next call from Flex it succeeds in the browser. For that reason I recommend to send a setRemoteCredentials(null, null) if you don't want the Flex user to be able to call any further methods unless he re-authenciates (bascially logs in again via some sort of login form which re-runs setRemoteCredentials() using valid credentials.
I tried to find other ways for logging the user out and looking through some of the AS sources in Flex, it appeared that ro.channelSet.authenticated may be a good flag for deciding if a user is logged in or not, however it always returned false for me regardless of whether or not the user was logged on... I tried logging the user out via ro.channelSet.logout() as well as ro.logout() but neither function seemed to actually do anything. If you have any idea if and how this is used with Remoting please let me know.
So all in all, keeping the slight caveats above in mind, the combination of CFCs with role based ecurity applied and the setRemoteCredentials() method on the RemoteObject class in ActionScript work well and are easy to implement. Unfortunately the documentation in Flash Builder only covers part of the process, and the CF docs cover another part - the CF side. It takes some work to string both parts together, but once implemented the process works pretty well. Now that I got my head around it I am ready to hook this into my control panel application.
You can download all sources (Flex and CF) in form of a Flash Builder project file here - note that you should rename the downloaded FlexCredentials.zip to FlexCredentials.fxp as it is a Flash Builder project file.