Introduction

One of the most important tasks for any dynamic application is providing the mechanisms to secure it and manage its users. In the past Cold Fusion developers have had very little guidance in creating these mechanisms. With the advent of MX technology from Macromedia we now have a set of common tools that can be applied and utilized not only in Cold Fusion, but also in richer Flash interfaces. This series of articles will explore the task of securing an application and managing users through a roles based component driven model.

Most security models handle three different functions ? Membership, Authentication and Authorization. A Member of an application should have the ability to join and edit their own information. Authentication can be resolved simply by answering the question ?Is this user a member of this application?? Authorization can be a bit more complex. Is the user authorized to see this Application? If they are authorized to see the Application are they allowed to view a particular file? If they can see the file which pieces of the file are they authorized to see? If they can see a piece of a file what data are they authorized to see?

Macromedia's MX technology gives developers the ability to handle complex tasks by breaking them up into self-contained Objects. The security model we will be building will have three main objects: member, role, and security. The goal in designing these objects is to make them generic enough to be reused in multiple applications and from multiple technologies. We will begin with a generic html interface to these objects and later on we will add a flash interface to the same objects.

Initializing the Sample Code

The sample code provided with this documentation is a fully functioning application that provides bothe the components necessary to administer a site and it?s users. This includes adding and editing both users and roles. All passwords are stored as hashed values for an additional layer of security.

The components handle all of the business logic necessary to run the application. I have provided Cold Fusion based views to allow you to interact with the application. These views can just as easily be provided by Flash or any other visual interface.

In order to initialize the code accompanied with this example the first user needs to be assigned to the Administrator role. This is accomplished with a block of code located in join.cfm on line 15. If you are going to be using this example it would make sense to delete that block of code after you sign yourself up as a user.

This article does not cover invoking components and relies on the self documenting features of Cold Fusion Components. All of the components are located in /com and you are encouraged to view them in a web browser to see the documentation.

The Big Picture? DB Structure

Our completed project is going to utilize the tables outlined above. The member table will store information about each member. Each member will have one or more related entries in the security table. The security table will store the member?s username and a hashed password. The roles table holds each of the roles for our application. The securityLink table links the security table to the roles and the security table.

Establishing the Framework 

Application.cfm

The cfsetting tag suppresses all output unless generated by Cold Fusion. 

	<cfsetting enablecfoutputonly="yes" />

In this example we need to initiate session and client management. We are going to set a cookie that stores the CFID and CFTOKEN so that we have the ability to track the user as they move through the application. We are going to use a data source entitled clientVariables to store client information. By using a database for client variable we remove any critical security information from the client machine.

	<cfapplication
    	name="cyberswat"
        clientmanagement="yes"
        sessionmanagement="yes"
        setclientcookies="yes"
        clientstorage="clientVariables" />

Application Wide Variables

In order to make the application as dynamic as possible we need to set a few application variables. Whenever declaring Application, Server, or Session variables it is important to lock the scope. We need to define a data source name, the web root of the application, and the root of the components our application will be using. Because these variables are applicable to all users we are going to place them in the Application scope. The settings below tell us the application uses the data source ?security?, can be reached form the url http://localhost/security/ and that our components are locate at http://localhost/security/com/

	<cflock scope="Application" timeout="10" type="Exclusive" />
        <cfparam name="Application.dsn" type="string" default="security" />
        <cfparam name="Application.webRoot" type="string" default="/security/" />
        <cfparam name="Application.cfcRoot" type="string" default="security.com" />
	</cflock>

cflogout

In our application authenticated users will have the ability to log out. The logout link will simply redirect the user to the current page they are looking at, but it will append the url variable logout=1. If this variable is defined we don?t want to process anything else before logging out the user. It is important that we place the We won?t need to redirect the user because our security system will be able to handle an un-authenticated user from any location. The cflogout tag removes knowledge of the user and users roles from the server. If the cflogout tag does not get called the user is automatically logged out when their session expires.

	<cfif isDefined("url.logout") AND url.logout>
    	<cflogout>
	</cfif>

cflogin

The cflogin tag and the processing it contains will only execute if we do not have a logged in user. We need to check for the existence of a cflogin scope which will get generated by Cold Fusion when a form named cflogin is submitted . The cflogin scope will always contain the variables cflogin.name and cflogin.password. If the cflogin scope is in existence we create a Security object that contains all the methods of the security component by using the createObject function to invoke security.cfc.

In order to authenticate the user we are going to call the authenticate method our Security object and pass it cflogin.name and cflogin.password. The authenticate method will either return a list of roles if the user passes authentication, or a 0 if the user fails. 

If the authenticate method has returned a list of roles we use the cfloginuser tag to log the user in and set the users roles.

	<cflogin>
    	<cfif isDefined('cflogin')>
        	<cfscript>
            	Security = createObject("component", "#Application.cfcRoot#.security");
                variables.roles=Security.authenticate(cflogin.name,cflogin.password);
                
            </cfscript>
            
            <cfif variables.roles NEQ 0>
            	<cfloginuser name="#cflogin.name#" password="#cflogin.password#" roles="#variables.roles#" />
            </cfif>
            
       </cfif>
	</cflogin>

The Header

The final line of the Application.cfm simply includes a header file. Our header is going to declare any UDFs we might need throughout the site and display a menu that is generated based on the users authentication state and roles. Please see that section for more detail.

	<cfinclude template="#Application.webroot#_dsp/dsp_header.cfm" />

OnRequestEnd.cfm

OnRequestEnd.cfm is another one of those ?special? cold fusion file names similar to Application.cfm. Unlike Application.cfm it get?s called at the end of each http request. It is an ideal location to place application wide error handling capabilities, but for the purposes of our example it only calls a footer file that we will use to close our html documents.

	<cfinclude template="#Application.webroot#_dsp/dsp_footer.cfm" />

login.cfm

The login.cfm page handles displaying messages and gathering the username and password for validation. This file introduces the concept of a JavaScript library that is beyond the scope of this article ? If you are building reusable, extendable web applications I strongly recommend you evaluate this concept.

The cflogin scope is. It is required that you use the fieldname j_username and j_password if using a form. The j_username gets mapped to cflogin.name and j_password gets mapped to cflogin.password. 

The login page will only get called if the person browsing the site tries to access an area they do not have rights to view. The processing that determines if the user can access a page happens before any content gets displayed. Therefore if the login page gets displayed we want to stop all other processing on the page so that any secured content does not get displayed. This is accomplished simply by placing a <cfabort> at the end of the login page. This effectively stops the user from viewing the content, displays a login page and a message, and is all accomplished without redirects and additional stress on the server.

The Security Checks

In this demonstration we are going to focus on two distinct types of security checks: Page Security, and Data Security.

Page Security

Page security applies to the entire page of content and all the items that may be contained in that page. An example of this type of security can be found in the document: /members/index.cfm.

Cold Fusion MX has provided a new function getAuthUser() which will return the name of an authenticated user. We begin by checking the length of getAuthUser(). If the length of getAuthUser()is zero we know that the user has not logged in and needs to view the login page. Otherwise we simply let them pass and do nothing ? pretty simple!

	<cfif not len(getAuthUser())>
    	<cfset request.loginmessage = "You need to login." />
        <cfinclude template="#Application.webroot#security/login.cfm" />
	</cfif>

Data Security

Data Level Security applies in instances where multiple users can view data but that data may change based on the users roles. An example of this type of security can be found in /_dsp/dsp_header.cfm and controls the menu.

There are three different states that we can check a user for: unauthenticated, authenticated, and member of a role. The first state (unathenticated) is simple and the one we are all used to. You simply output whatever data you want the unathenticated user to see:

	<cfoutput>
    	<a href="#Application.webroot#">Home</a>
    </cfoutput>

We check for an authenticated user as outlined in the Page Security section. By Evaluating the length of the function getAuthUser() we can easily determine if the user has logged into our application. Using this method we ensure that our data is protected from all unauthenticated users.

	<cfif len(getAuthUser())>
    	<cfoutput>
        	<a href="#cgi.script_name#?logout=1">Logout: #GetAuthUser()#</a>
        </cfoutput>
    </cfif>

The final check is to see if a user is a member of a particular role that we have defined. Cold Fusion MX provides us with the function isUserInRole(?role_name?) which returns true or false.

	<cfif isUserInRole("Administrator")>
    	<cfoutput>
        	<a href="#Application.webroot#member/admin.cfm">Administer Members</a>
        </cfoutput>
	</cfif>

By utilizing the security functions provided by Cold Fusion MX we can easily secure any application in a flexible manner.


NOTE: You may also (Download Code attached)

About This Tutorial
Author: Kevin Bridges
Skill Level: Advanced 
 
 
 
Platforms Tested: CFMX
Total Views: 273,918
Submission Date: December 17, 2002
Last Update Date: August 25, 2011
All Tutorials By This Autor: 1
Discuss This Tutorial
  • great tutorial, Kevin, easy to read and understand. i have one sticky problem regarding login methods and i was hoping you might be able to point me in the right direction: i let users create their own accounts. but now, i would like to know when a user is creating multiple accounts. i was thinking to: 1. when user tries to log in, set a temp cookie using JavaScript (to make sure user's browser allows both JavaScript and cookies) 2. if it works, delete temp cookie. if not, block login 3. if not exists, set a permanent cookie containing the user's id 4. when someone creating a new account, check for permanent cookie but i sure there must be a better way to do this! thanks ion

  • Sorry, I stopped writing ColdFusion altogether and haven't even looked at this article in a long time. Pretty interesting it is still as popular as it is. Sounds like there is a bit of confusion centered around the clientVariables datasource. If you get something like this "The data source named "ClientVaribles" is not a valid client storage DSN" it is because you have not established the datasource as client variable storage in the coldfusion administrator. When you do that step correctly the cf administrator will create a couple of tables in the database. The benefit of using a datasource instead of cookies is multi-fold. From a security perspective it is good because the end client will never see the data you are storing ... whereas if you were to use a cookie it would be easy to see what you are storing and easier to modify it. Secondly, you will eventually want to store more complex objects as client variables. Say, for example, you create a structure that represents the user and has several keys, one of which is an array, one of which is a query, and one of which is another sturcture. You can serialize the structure using the wddx tags and store the resulting string in a database. The wddx string can get quite long depending on the complexity of the data. There is a definite limit as to how long of a string you can store in a cookie that you can circumvent with the clientVariables datasource. So, in a nutshell, you get additional security and a wicked cool storage mechanism for complex data types. To the person asking the list of questions: 1. clientVariables (about the 9th paragraph in the article) 2. security (about the 10th paragraph in the Application.dsn variable) 3. It's a very good thing to get in the habit of. 4. You have the ability to place cfc's anywhere in the directory structure or even on the machine in non web accesible folders. The cold fusion documentation goes into great effort to explain the process in detail. I placed the cfcs in this example under a web accesible directory to avoid explaining how to customize the location since the cf documentation does that so well. The naming convention is roughly borrowed from java standards. Unfortunately it does seem extremely picky when you first start using that syntax, but your slowly walking into the java underbelly of cf. When I first started using cfcs I did not understand that particular syntax ... now it's very rare that I use /this/that syntax. Best bit of advice I can give you is to spend some time going through the cf docs ... that is an extremely important concept for you to understand. 5. doh ... not sure how the /castlefnord/securityBack directory got stuck in there, my apologies. Could you be more specific about the problem it is causing? If memory serves correctly that was literally just a backup directory for the article and shouldn't interfere with anything, but it has been a while. Hope that helps! Kevin Bridges cyberswat.AT.gmail.DOT.com

  • Ok, I played with this for a little while trying to be a smart kid... managed to get a few things working, however... still fairly confused. I think what we need clarification on is the following: 1. clientvariables.mdb - what is the datasource name? 2. security.mdb - what is the datasource name? 3. Setting clientVariables in the Server Settings (new to me) - but I did it. 4. Please explain how we need to set up the #Application.cfcRoot# deal. It seems this is a very pickey piece of the code. Does the site HAVE to be in a certain folder/area on my comp? How can we edit that to work? 5. I have no /castlefnord/securityBACK/ folder with the download and that is causeing problems too. Sorry about this, I'm just trying to learn as much as I can from these tutorials (as Im sure many others are as well) and unfortunatly that means I need a touch more explination at times. I appreciate any help you can give. Thanks.

  • Can someone please explain to me where the two dbs come into this? I set up the clientVariables DB as a DSN, my hosts went to the CF Administrator page. Under SERVER SETTINGS, click on Client Variables. I get an error as it doesn't have a table called state in it. The key words are "client storage" DSN. This is really tricky tutorial!

  • All the .cfcs got to be registered?

  • What causes the login page to pop back after a successful login? I have my application page in the root directory. The cflocation after login is another cfm page. Is that the reason? If it is what can I do? Thanks John

  • it might also help if you spell Variables right in ClientVariables -- you don't have the "a" in the word.

  • Bill, i had the same problem you did with the DSN. Notice the error message reads "Please define client storage dsn via the admin pagea." The key words are "client storage" DSN. After you set up the clientVariables DB as a DSN, go to your CF Administrator page. Under SERVER SETTINGS, click on Client Variables. Select the clientVariables DB from the DSN list to add as a client store. That should get you past that problem. Great tutorial btw.

  • I installed the pages you had done along with the DB's and set the DSN in the mx admin page but i am getting this: The data source named "ClientVaribles" is not a valid client storage DSN. Please define client storage dsn via the admin pages. The error occurred in C:\CFusionMX\wwwroot\security\Application.cfm: line 3 1 : 2 : 3 :

  • I tried to setup the downloadable files in my machine, But realy I am confuse How I begin and what is the starting point please help me!

Advertisement

Sponsored By...
Mobile App Development (IOS, Android, Cordova, Phonegap, Objective-C, Java) - Austin, Texas Mobile Apps - Touch512, LLC.