Doug's Resume
OO Lexicon
Chat with Doug!
Recent Entries
You may also be interested in...

hotels boeken in 7 sec
Engagement Rings
Online Dating Australia




<< July, 2008 >>
SMTWTFS
12345
6789101112
13141516171819
20212223242526
2728293031
Search Blog

Recent Comments
Re: American Airlines, YOU SUCK! (by LKJ at 7/23 10:35 AM)
Re: American Airlines, YOU SUCK! (by delavega at 7/18 3:12 PM)
Re: Using Google as your CF Mail Server (by darwin at 7/18 2:47 PM)
Re: American Airlines, YOU SUCK! (by Joe at 7/17 9:29 AM)
Re: My Approach to Basic Security in a Model-Glue Application (by Jeffrey Smith at 7/10 11:53 PM)
Re: My Approach to Basic Security in a Model-Glue Application (by dougboude at 7/10 5:14 PM)
Re: My Approach to Basic Security in a Model-Glue Application (by Jeffrey Smith at 7/10 2:00 AM)
Re: Basic Security in Fusebox 5.5.x (sans XML) (by Matt Jones at 7/09 10:07 AM)
Re: Basic Security in Fusebox 5.5.x (sans XML) (by Matt Jones at 7/07 1:16 PM)
Re: Just What IS a 'Service Layer', Anyway? (by Keith DeWeese at 7/04 9:07 AM)
Categories
Archives
Photo Albums
Funnies (5)
Family (3)
RSS

Powered by
BlogCFM v1.11

05 July 2008
Helpful Hint for Retrieving CFGRID via Ajax

Here's the scenario...

You're building a Model-Glue application and you're using some Ajax calls to retrieve some data displayed within a CFGRID. When you navigate directly TO the event that performs the Ajax action (index.cfm?event=ajax.getDataSetforEdit&dataSetID=2 , for instance) the page loads just fine and renders the grid without a hitch. When you attempt to retrieve and display it by updating the innerHTML of a target DIV tag, however(something like:

new Ajax.Updater('datatarget','index.cfm?event=ajax.getDataSetforEdit&dataSetID=2',{method:'post',evalScripts: true});

 

)    your browser complains (see the error messages below) and the grid doesn't display!

 

 

 

              Symptom as seen in IE7                                                        Symptom as seen in Firefox's Firebug window

The first thing you need to do is to make SURE that you have a proper server mapping to the CFIDE directory. Not a COLDFUSION mapping, but a WEBSERVER mapping. In IIS you create a virtual directory pointing to CFIDE; in Apache you edit the http.conf file and add an Alias (see my buddy Jim Pickering's post for details on how to do this in Apache). After ensuring that I indeed DID have a proper mapping, I was STILL getting the error...dig dig some more. I finally came across a single, obscure tidbit that turned out to be the answer to the challenge:

 When retrieving and displaying data in a CFGRID via Ajax, your parent page must import the CFGRID library by adding the line: 

<cfajaximport tags="cfgrid" />

 

Typically you don't have to worry about importing any libraries, but in the case of utilizing Ajax to render the grid, you do. In my situation, I'm using Prototype to perform my Ajax calls, so I'm certain this scenario doesn't just apply to those using CF's built in Ajax functionality (and in fact, may not apply at all in that case! I don't know that for sure though).

Anyway, just wanted to post this in case it saves anybody else some time (and so I can reference it next time I run into this and have completely forgotten what the underlying cause is).

Doug out.

Posted by dougboude at 2:59 AM | PRINT THIS POST! | Link | 0 comments



03 July 2008
Basic Security in Fusebox 5.5.x (sans XML)
I have recently begun a project using the latest version of Fusebox (5.5.1). This is my second forray into Fusebox 5x, but the first one wasn't much more than a hello world for my own benefit. This time, I'm taking the "sans XML" approach and using FB in its MVC arrangement to build an application that is primarily a data management tool utilizing Java proxies exclusively as its means to communicate with a backend Oracle database. So, as I learn things along the way, I'm going to be sharing them as blog posts in order to possibly give others some stepping stones as they traverse their own FB "sans XML" J-curve.

I should also say that I am coming to Fusebox 5.5 after having exclusively used Model-Glue v2 for the past year and a half or so. Since one's natural approach is to try and equate what you already know from your current framework of choice to the one you are now learning, that is what I will be doing as well, so you may often see me reference things in Model-Glue terminology to help bridge the knowledge gap. In fact, one of the first things I did was to rename my fuseaction to "event", just to make me feel a little more at home. :)

Okay, so one of the first things I needed to create for this app was some basic security; if the user is not logged on, they don't get past the first page, period. Though there are always many solutions to the same challenge, following is my own approach to the matter.

Step 1 is find the best place within the Fusebox event lifecycle (which I STILL don't fully know, nor could I find any clear documentation on) in which to "intercept and potentially redirect" our call. Basically, before our user arrives at their destination page, we want to see if it is a secured page (which all of mine are except for the login) AND if the user has already successfully authenticated, then redirect them to the login page if needed.

In order to maintain the user's state (keep track of whether or not they logged in, store their personal info in a handy, globally available package), I created a User.cfc that I make sure has been instantiated with an initial 'loggedin' setting of false (this is built into the CFC's init method), and placed into the session scope. In Fusebox 5.5.1, the most appropriate place to do this that I found is in the Application.CFC's "onRequestStart" method. Mine looks like this:

<cffunction access="public" name="onRequestStart" output="false" returntype="void" hint="I am the code to execute at the beginning of a request. ">
    <cfargument name="targetPage" />
    <cfset super.onRequestStart(arguments.targetPage) />
    <!--- formerly in fusebox.init.cfm --->
    <cfset self = myFusebox.getSelf() />
    <cfset myself = myFusebox.getMyself() />

    <cfif not structkeyexists(session,"user")>
        <cfset session.user = createObject( 'component','model.user').init()/>
    </cfif>
   
    <!--- making our user object available in the event bean. Event is created by Fusebox and is available to us at this point. --->
    <cfset event.setValue("user",session.user) />
</cffunction>


Notice that we are doing a call to "super.onRequeststart". This is because our Application.cfc is extending (<cfcomponent extends="fusebox5.Application" output="false">) Fusebox's Application.cfc, so we need to make sure the framework gets to execute its onRequestStart as well. If we didn't make the 'super' call, our method would override FB's method and things just wouldn't go well at all.

Okay, so now with every request, I ensure that I have at LEAST an empty user object in session. The remainder of the onRequestStart method places my user object into a handly little bucket Fusebox provides us called (thankfully) 'Event'. This works very well for me, as in Model-Glue it's ALL ABOUT the event, my brutha from anotha mutha. By putting user into 'event', i can access it from anywhere else in my application WITHOUT having to talk directly to session ( a big OO No No, for the most part).

Now, the request still has not yet arrived at its destination page, and Fusebox has another file yet to process before it renders any content: Fusebox.init.cfm.

Though I tried madly to do all of my intercept and redirect within application.cfc, alas I could not make it work. Feedback from Mr. Corfield affirmed that indeed application.cfc was not the best place to do what I was trying to do, anyway, and directed me to fusebox.init.cfm as the most proper location to perform any needed manipulation of the target fuseaction. Here is the content of my fusebox.init.cfm file:

<!--- ************ SECURITY CHECK! ***************** --->
<!--- if we're not authenticated and our current fuseaction is NOT our default fuseaction (in order to avoid a dreaded infinite loop), make it so --->
<cfif (not structkeyexists(session,"user") OR not session.user.getLoggedin()) AND attributes.fuseaction IS NOT myFusebox.getApplication().defaultfuseaction>
    <!--- if user is not logged in, replace the current fuseaction/event name with our default --->
    <cfset myFusebox.relocate(url=myFusebox.getApplication().myself & myFusebox.getApplication().defaultfuseaction) />
</cfif>



As you can see, i'm doing a simple check of the user object and the target fuseaction. If the user isn't logged in (or user object doesn't exist for whatever reason) AND our target fuseaction is something OTHER than our default fuseaction (login), then we're leveraging the fusebox 'Relocate' method to force the user to our login page.

That's it, it's that simple. If I had to do fuseaction level security, or individual page security, I think I'd probably STILL perform those actions at these exact same locations, only I'd be adding in additional checks for the user's roles and the fuseaction's security level.

Feedback on my approach solicited. :)

Doug out

 

UPDATE TO PREVIOUS POST (7/9/08)

Based on the comments I received, I made a little time to pursue the route I had proposed for implementing role/fuseaction based security and found that I could do it easily without having to add any more controllers or fuseactions. Building on all of the code above, I simply added to my user object a 'Roles' variable that contains a list of the authenticated user's roles. I then added to my global configuration bean an item 'publicFuseActions' that contains a list of the fuseactions I am NOT securing (since those are far fewer than the ones I AM securing...I could've easily reversed the contents of this list to contain FAs that ARE secured). Lastly, I made a modification to the security check in my fusebox.init.cfm to evaluate the following:

(

the user is NOT logged in

OR

user IS logged in AND the requested fuseaction IS a secure one AND the authenticated user does NOT have the appropriate role

)

AND

our requested fuseaction is NOT our default fuseaction

If the entire statement above evaluates to true, then our user needs to be redirected to the login page.

Here is my fusebox.init.cfm that accomplishes the above logic:

 

<cfif ((not structkeyexists(session,"user") OR not session.user.getLoggedin()) OR (listfindnocase(application.globals.config.getConfigSetting("publicFAs"),attributes.fuseaction) eq 0 AND listfindnocase("Admin",session.user.getRoles()) eq 0)) AND attributes.fuseaction IS NOT myFusebox.getApplication().defaultfuseaction>
 <cfset myFusebox.relocate(url=myFusebox.getApplication().myself & myFusebox.getApplication().defaultfuseaction) />
</cfif>

 

Again, I have to ask what would be the motivation/need to create additional controllers and fuseactions to perform security/role based fuseaction routing when the single IF statement above, strategically placed, accomplishes it just fine? Am I over-simplifying things? (or is it really just that simple?  ) . If I wanted to get even more elaborate, such as routing based on role, or a diversity of messages to match the situation, I would probably add a message dictionary to my global config bean and replace my growing IF statement with a call to a global security object that would perform appropriate evaluations and return the needed responses for me to execute an appropriate redirect and message. One more object in my model that I create as a singleton and have available to my fusebox.init.cfm...why complicate it any more than that? Again, input solicited.

Doug out. again.

 

Posted by dougboude at 1:51 PM | PRINT THIS POST! | Link | 4 comments