Friday, July 25, 2008    
Home My Books Blog ColdFusion About Me Back    

Calendar
<< Nov 2007 >>
S M T W T F S
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  

Search

Categories
 • Adobe (63) [RSS]
 • AdobeMAX06 (45) [RSS]
 • AdobeMAX07 (59) [RSS]
 • AdobeMAX08 (14) [RSS]
 • AIR (116) [RSS]
 • Appearances (115) [RSS]
 • Books (67) [RSS]
 • CFEclipse (14) [RSS]
 • ColdFusion (1121) [RSS]
 • Data Services (8) [RSS]
 • Flash (95) [RSS]
 • Flex (346) [RSS]
 • Jobs (88) [RSS]
 • JRun (12) [RSS]
 • Labs (27) [RSS]
 • LiveCycle (17) [RSS]
 • MAX (149) [RSS]
 • Regular Expressions (12) [RSS]
 • SQL (36) [RSS]
 • Stuff (499) [RSS]
 • Tips (CF Studio) (80) [RSS]
 • Tips (CF) (795) [RSS]
 • Tips (Dreamweaver) (91) [RSS]
 • Tips (Flex Builder) (2) [RSS]
 • Using CF (133) [RSS]
 • Wireless (97) [RSS]

Other BLOGs
 • Charlie Arehart
 • Lee Brimelow
 • Ray Camden
 • Christophe Coenraets
 • Sean Corfield
 • Mihai Corlan
 • Cornel Creanga
 • John Dowdell
 • Danny Dura
 • Enrique Duvos
 • Steven Erat
 • Kevin Hoyt
 • Serge Jespers
 • Adam Lehman
 • Duane Nickull
 • Miti Pricope
 • Andrew Shorten
 • Ryan Stewart
 • James Ward
 • Greg Wilson
 • Full As A Goog

RSS Feeds
 • Feed
 • Subscribe

Join my mailing list and find out about new books and other topics of interest.

Thoughts, ideas, tips, musings, and pontifications (not necessarily in that order) by Ben Forta ...
NOTE: This is my personal blog, and the opinions and statements voiced here are my own.

Viewing By Entry / Main
November 15, 2007

Flex And ColdFusion Session Variables

A year or so ago I posted an entry explaining why, as a rule, managing session state on the server (as ColdFusion does) was not ideal in Flex applications. I still stand by that assertion. But, many have pointed out that it is sometimes necessary to access ColdFusion session data from within Flex applications. Indeed, I was asked about this several times in the past week alone. And so, time to update the topic.

ColdFusion stores session variables on the server. In order to know which subset of session data belongs to a specific client, ColdFusion creates an identifier that is sent to the client (usually as cookies, but it could also be a URL parameter). The identifier must be sent back to ColdFusion on each and every subsequent request so that ColdFusion may make the correct server-side session data available. Without the identifier, ColdFusion will assume that there is no active session, and will the create a new session and attempt to send a new identifier to the client.

Flex applications run within the Flash Player, not within ColdFusion. As such, Flex applications have no direct access to ColdFusion session data. But, if you were to create a Flex application with a ColdFusion back-end, that Flex application could indeed gain access to ColdFusion session data as needed. Here's how it works.

The preferred way for Flex to connect to ColdFusion is via Flash Remoting - using AMF to connect to a ColdFusion Component. AMF actually communicates back to ColdFusion via HTTP and the web browser. As such, if ColdFusion's session identifier exists in the browser, it will be sent back with Flash Remoting requests. Similarly, if the browser receives identifier cookies along with AMF results, those cookies will be saved. In other words, when you use to connect to a ColdFusion Component, ColdFusion is fully aware of session state management, and the CFC being invoked automatically has access to the correct session data.

But, how can Flex get to that data? The answer is it can't, but you can create a CFC that exposes session variables.

Caution: Before you go further I will point out the obvious. If you create a public facing CFC that exposes methods that allow session data to be directly manipulated, well, you've now allowed public access to session data. Of course, callers will only have access to their own session data, but still, proceed with caution, and make sure you fully understand what you are doing.

Ok, here is the session.cfc file:

<cfcomponent>

   <!--- Set a CF session variable --->
   <cffunction name="set" access="remote">
      <cfargument name="name" type="string" required="yes">
      <cfargument name="value" type="string" required="yes">

      <!--- Set SESSION var --->
      <cfset SESSION[ARGUMENTS.name]=Trim(ARGUMENTS.value)>

   </cffunction>


   <!--- Get a CF session variable --->
   <cffunction name="get" access="remote" returntype="any">
      <cfargument name="name" type="string" required="yes">

      <!--- Init local var --->
      <cfset var result="">

      <!--- Get SESSION var if it exists --->
      <cfif StructKeyExists(SESSION, ARGUMENTS.name)>
         <cfset result=SESSION[ARGUMENTS.name]>
      </cfif>

      <!--- Return it --->
      <cfreturn result>

   </cffunction>


   <!--- List session variable names --->
   <cffunction name="list" access="remote" returntype="array">

      <!--- Return it --->
      <cfreturn ListToArray(ListSort(StructKeyList(SESSION), "text"))>

   </cffunction>


   <!--- Keep alive --->
   <cffunction name="keepAlive" access="remote">
      <!--- Nothing to do here --->
   </cffunction>


</cfcomponent>

As you can see, the code is pretty simple. SESSION is actually a ColdFusion structure, and so direct session access is possible using CFML structure functions. The "list" method returns an array of session variables (their names). The "get" method gets the contents of a specific session variable. And the "set" method sets a session variable, creating or updating as needed (this example only creates simple variables). The final method, named "keepAlive" does nothing, and it can be called as needed to keep the session alive (ensuring that it does not time out).

To help test the app (and to populate it with data) you can use a simple test page like this:

<!--- Init vars --->
<cfparam name="FORM.varName" default="">
<cfparam name="FORM.varValue" default="">

<!--- Process form if submitted --->
<cfif Trim(FORM.varName) NEQ "" AND Trim(FORM.varValue) NEQ "">
   <cfinvoke component="session"
            method="set"
            name="#Trim(FORM.varName)#"
            value="#Trim(FORM.varValue)#">

</cfif>

<!--- Dump SESSION scope --->
<cfdump var="#SESSION#">

<!--- Form --->
<hr>
<cfform action="#CGI.SCRIPT_NAME#">
Variable:
<cfinput type="text" name="varName" required="yes">
Value:
<cfinput type="text" name="varValue" required="yes">
<br />
<cfinput type="submit" name="sbmt" value="Save SESSION variable">
</cfform>

How to use session.cfc from within Flex? Here is a simple example application:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="vertical" width="100%" height="100%"
   creationComplete="initApp()">


   <mx:Script>
      <![CDATA[
         import flash.events.TimerEvent;
         import mx.utils.ObjectUtil;

         // Timer thread handle
         private var timer:Timer;

         // Initialize app
         private function initApp():void
         {
            // "Keep alive" interval
            var pingSeconds:int=60;

            // Get session list
            session.list();

            // Create "keep alive" timer
            timer=new Timer(pingSeconds*1000);
            timer.addEventListener("timer", timerHandler);
            timer.start();
         }

         // Timer handler
         private function timerHandler(event:TimerEvent):void
         {
            // Ping CF session to keep alive
            session.keepAlive();
         }

         // Get a CF session variable
         private function sessionGet(varName:String):void
         {
            // Get it
            session.get(varName);
         }

         // Set a CF session variable
         private function sessionSet(varName:String, varValue:String):void
         {
            // Save it
            session.set(varName, varValue);
            // Update list
            session.list();
         }
      ]]>
   </mx:Script>

   <!-- Define CFC -->
   <mx:RemoteObject id="session"
                  destination="ColdFusion"
                  source="CFFlex.session"
                  showBusyCursor="true" />


   <!-- GET panel -->
   <mx:Panel width="100%" height="100%"
         title="ColdFusion SESSION Variables">

      <mx:HBox width="100%" height="100%">
         <!-- List fo session variables -->
         <mx:List id="sessionList"
               dataProvider="{session.list.lastResult}"
               click="session.get(sessionList.selectedItem)"
               height="100%" width="200"/>

         <!-- Display value -->
         <mx:TextArea text="{ObjectUtil.toString(session.get.lastResult)}"
               editable="false"
               width="100%" height="100%" />

      </mx:HBox>
   </mx:Panel>

   <!-- SET panel -->
   <mx:Panel width="100%" height="150"
         title="Set ColdFusion SESSION Variable">

      <!-- Variable create form -->
      <mx:Form width="100%" height="100%">
         <mx:FormItem label="Variable:" width="100%">
            <mx:TextInput id="varName" width="100%"/>
         </mx:FormItem>
         <mx:FormItem label="Value:" width="100%">
            <mx:TextInput id="varValue" width="100%"/>
         </mx:FormItem>
         <mx:FormItem>
            <mx:Button label="Save"
               click="sessionSet(varName.text, varValue.text)"/>

         </mx:FormItem>
      </mx:Form>
   </mx:Panel>

</mx:Application>

The application features two panels. The first displays a list of ColdFusion session variables (by calling the session.list() method), allowing them to be selected to display their contents (by calling the session.get() method). The second contains a form that can be used to create new session variables (by calling the session.list() method). To ensure that the ColdFusion session does not time out, a Flash timer is defined, and it pings the keepAlive() method (once a minute in this example).

Now, I would still caution you by saying that, as a rule, if data needs to persist it should persist on the client, within the Flex application. But, when you do need access to ColdFusion session data, this technique will do the trick.

Updated 11/16/2007 to add timer and keepAlive logic.

Related Blog Entries

TrackBacks
There are no trackbacks for this entry.

No trackback URL. Trackbacks are only allowed via interactive form.

Comments
Ben, great example, thank you - I actually expected this to be alot harder that it was. Just a quick question - what is it that "links" the flex app to the created session. I nearly expected to see a "urltoken" being passed when I first started reading the post. Is the relationship to the session CFC maintained by the connection opened in the Flex app, or is it done via the browser?

Also, there are different ways to manage sessions in CF (cookies, database, J2EE, etc), will this method work with them all?

Cheers,

Davo
# Posted By David | 11/16/07 12:03 AM
David, it works just like regular sessions work. As the request is routed via HTTP and the browser, the same CFID/CFTOKEN cookies are set and passed back and forth. If cookies are not used then it'll be trickier, as you'd need to pass the identifier manually.

--- Ben
# Posted By Ben Forta | 11/16/07 7:13 AM
Thanks for the update. However, you still don't address the issue of keeping the session from timing out, do you have any insight to this matter?

To clarify, the flex app running in the flash player does not refresh the browser, and so after about 20 minutes the session times out and is rendered useless. If it is not possible to increase the timeout value for sessions passed 20 minutes due to limitations imposed by the server administrators, you are %@&#.

Is there a way to use remoting to refresh the session and/or keep it alive? Or are we stuck with a sessionless solution?
# Posted By Clint | 11/16/07 7:47 AM
Clint,

Sure, all you need to do is ping a CF page or CFC method on the server ever n minutes. For example, add a CFC method called keepAlive() which does nothing, and use an ActionScript timer to invoke it every few minutes. Problem solved.

--- Ben
# Posted By Ben Forta | 11/16/07 8:07 AM
Clint,

I just updated the example to include the keepAlive logic I was referring to. The example now pings the server once a minute, just to keep the session alive.

--- Ben
# Posted By Ben Forta | 11/16/07 10:16 AM
Fantastic, thanks Ben.
# Posted By Clint | 11/16/07 10:20 AM
Ben, you say if data needs to persist it should persist on the client (the flex application). How can this be secure? If I store the fact that a client is authenticated, or that their user_id is N, whats to stop them from modifying that data as its passed back to the server? Say when the getAccountDetails(user_id) method is called or whatever.

Instead we've been doing getAccountDetails(), (without passing in a user_id parameter) and then internally the getAccountDetails method always looks to Session.user_id.
# Posted By Ryan Stille | 11/16/07 2:00 PM
Ryan,

I agree, there is persistent data and then there is persistent data. While the authenticated user id should definitely be tracked in the client, it must be validated on the server (although users can always change session identifiers, user tampering is a reality either way, and it must be dealt with). But, other data, like contents of a shopping cart, definitely belong on the client. I guess we need them both.

--- Ben
# Posted By Ben Forta | 11/16/07 2:30 PM
Ben / Ryan,
Your replies bring up great points - so if I may ask a follow up question (that may be slightly OT) - how secure is the persistent data stored in the Flash Player. So, if user_id is passed from your CFC to Flex, is it possible for the user to then manipulate the user_id to do some snooping in your system? I was always under the impression that the flash player was secure from such manipulation.

Thanks,

David
# Posted By David | 11/16/07 3:33 PM
I'll let Ben comment on the security of the flash player itself - but its fairly easy to run the AMF/HTTP data through a proxy where I could manipulate the data as it passes through. There are also FireFox extensions that will record the AMF/HTTP data, allow you to change it, and then play it back - thus bypassing the flash player all together.
# Posted By Ryan Stille | 11/16/07 3:42 PM
David, regardless of the client used, as a rule, anything on the client can be changed, and whatever is sent over the wire can be intercepted. Which is why server side validation is never optional.

--- Ben
# Posted By Ben Forta | 11/16/07 4:16 PM
Fantastic, thanks.
But one problem: when I use HttpService, such as when I call HttpService.send(http://...), also the server need an user identification. Than how we can send the session value the same time?
# Posted By Kono | 11/21/07 8:13 AM
There are some situations the flashplayer won't send along the cookies at all.. I forgot if it was IE on windows or Firefox on windows though..
# Posted By Evert | 11/21/07 5:51 PM
Ben, I read your previous article several times before setting up my integrated flex / cf site with common authentication and data model (in CFC's). This one validates the reasons and approach I ended up going with.

Hope this isn't too off topic...I'm using a combination of PureMVC in Flex and Coldbox on the CF side. Because the coldboxproxy exposes the Coldbox handlers and Coldbox provides session access plugins (along with a lot more) creating mixed XHTML/Flash apps with shared data and communication has been pretty easy. The Coldspring integration, interceptors, logging, caching and debugging features of Coldbox are also great and using the coldboxproxy they are easily applied to the AMF requests coming from Flex. Setting up a generic coldboxproxy Business Delegate in PureMVC with specific handlers called from Proxies was easy (one I got my head around all the OO / design patterns stuff). Hope some of this is useful to others, I'm still figuring a lot of it out.

Thanks to Luis (Coldbox) & Cliff (PureMVC), their frameworks rock and they are both very supportive and responsive to feedback and questions. Thanks again to you Ben, I got started with CF 2 and your books really helped along the way.

Chris
# Posted By Chris | 11/27/07 8:55 PM
Hi Ben,
In your session.cfc, is it best practice to use cflock when using the set and get methods?
Thanks in advance!
Andrew
# Posted By andrew | 12/6/07 3:33 PM
Andrew, I am not sure I'd call it a 'best practice', misused it could be far from the best anything. But, if you are concerned about race conditions, then yes, use a session lock.

--- Ben
# Posted By Ben Forta | 12/6/07 7:14 PM
ok, anything on the client is accessible/changeable. I use MVC for my flex application. Model of the MVC stores all my data in the form of value objects. these data are exposed through the controls and databinding. I make service calls to php services to save data in the database. what is the security issue involved with this type of architecture?
# Posted By adam king | 2/7/08 12:42 PM
I try to run the example:

the CF testpage works fine, but the Flex App returns the following error:

Unable to invoke CFC - Variable SESSION is undefined.
# Posted By Alex | 4/8/08 3:17 AM
Quick question on this topic of sessions, flex and coldfusion:
1. When the user logs in and is verified I store a hashed (cftoken + username) on the client side.
2. I also update that into the my webuser table of the database.
3. Then everytime the user sends a request through flex I have a cfc w/ stored procedure that checks against the hashed(cftoken + username) and cftoken in the database.
4. OnSession end it clears it from the database table.

* I always check user permissions server-side against the database

Wouldn't this for the most part keep everything as secure as a standard coldfusion web app?

If this is basic I apologize... just started using Flex
# Posted By Steve | 4/9/08 10:36 PM
Where are you Ben? You need to answer a few questions here. When did you last check your blog?
# Posted By adam king | 4/18/08 8:17 AM
Alex, that probably means the session identifier is not being passed. You need to verify that.

Steve, yes, that will indeed keep things as secure. But the main reason to keep client state information on the client is less about security and more about performance, manageability, and the fact that that is where it belongs. The reason that we store client session state information on the server in web apps is not because that is where it belongs, it's because of a fundamental limitation of the wen in that it is stateless. Flex apps do not have this limitation. So it is less about doing things the way we do in web apps, and more about not having to resort to doing so. Of course, some things do belong on the server, like login timeouts. But other things belong on the client.

--- Ben
# Posted By Ben Forta | 4/18/08 8:46 AM
What would you recommend to be the best way to lock the CFC down from malicious access?
# Posted By Scott | 5/1/08 12:38 AM
Ben,

Can you tell me what you means with "...that probably means the session identifier is not being passed. You need to verify that...", please?
# Posted By Alex | 6/6/08 4:55 AM
Alex, it means that the CFID/CFTOKEN or jsessionid cookies/URL parameters are not being passed, and need to be.

--- Ben
# Posted By Ben Forta | 6/6/08 11:27 AM

  © Copyright 1997-2008 Ben Forta, All Rights Reserved