Welcome!

ColdFusion Authors: Yakov Fain, Pat Romanski, Liz McMillan, Maureen O'Gara, Greg Ness

Related Topics: ColdFusion

ColdFusion: Article

Security Made Simple

Security Made Simple

One of the most common requests made of developers is that they create a password-protected area on a site, be it for registered users or administrative functions.

Ideally we'd like to have a system that automatically detects if users are logged in when they access a page and sends them to a login page if they're not. We also want to keep track of the users' state when they log in, so we can send them on to their original destination after the login process. Of course, this system would also be easy to implement with a minimal amount of effort on our part.

We can accomplish all these goals by using session variables and Allaire's application framework. Session variables allow us to check which users have logged in, while the framework gives us an easy way to implement security across multiple templates without additional work.

Logging In - The Simple Way
Let's start out with the basics: Why do I want to use the application framework file for security? For those not familiar with the application framework, the application.cfm is a special file that's run before any other ColdFusion template in the same directory or subdirectory. It's like cutting and pasting the code from the application.cfm into the top of each template. This model automatically provides security to all the ColdFusion templates in a directory without changing them. In addition, any new templates created in the directory are protected without any additional work.

How does this type of security work? CF provides a convenient method for tracking individual users called sessions. The session stays with the user and is used to create variables that are accessible only to that user. For our security system we want to place an indicator in the user's session when he or she logs in. We can then check the indicator to see if the user is logged in. A good variable to use for this is the user's ID; it also comes in handy when we want to provide customized information for the user. If the user isn't logged in, we can redirect him or her to a login page. When we place this check in the application.cfm, it protects all the pages in its directory because the check is run before any other code in a template. A sample application.cfm might look like:

<CFIF NOT IsDefined("Session.user_id")>
<CFLOCATION URL="login.cfm">
</CFIF>

The login.cfm asks for the user's login name and password and then sets the user ID in the session variable. The next time the user tries to access a protected page after logging in, the session variable is defined and the code ends, allowing the rest of your template to execute.

Logging In - One-Stop Security
Hopefully you get the general idea and may have seen or used a similar system in other sites. However, we want more functionality from our security system. The first modification I make is to encode the login page within the application.cfm. This gives our model three advantages:

  1. We don't have to track which page the user was trying to access.
  2. All of the security procedures are contained within a single file.
  3. It allows us to pass on form variables.
When using this model you don't need to keep track of the templates the users were going to before they were required to log in. Why? Because they're still on the template they were trying to access. The application.cfm interrupts the normal functionality of a template and checks to see if users are logged in. If not, it displays a login form. The login form submits back to the template that they're on, which is again interrupted by the application.cfm that processes the login. If the login is okay, the normal functionality of the template is allowed to run.

At this point you're probably scratching your head, so here's a description of what you would see when using the model. You click on a link to the report.cfm template that has restricted access and aren't logged in. A form shows up asking for your login and password, but you see the report.cfm page in the URL. The application.cfm has interrupted the normal functionality of the report.cfm page and displayed the login form. Enter your login and password and you see the report you were expecting and you're still on the report.cfm page. The login form submitted back to the report.cfm page, which was interrupted by the application.cfm that processed the login and then ended, allowing the report to run normally. The next time you try to access the report.cfm you won't be prompted to log in because your session variable is now set.

With the login and login processing all in the application.cfm, we have a one-stop shopping security system. We drop the file in a directory, make a few modifications and we have security for all our templates. This system is very reusable; I have implemented it on several consulting engagements.

In the simple system we used a redirect to send users to the login page; when that happens we lose our ability to pass form variables and keep them as form variables. Using the improved system, we take all the form variables that were passed in the protected template and place them in hidden form fields along with the login name and password. When the login form is submitted, these variables are passed along with the form and can be accessed as the template expects them.

Code Walk-Through
The first thing we have to do in our application.cfm is to turn on the session variables - the foundation of our tracking system (see Listing 1). Then we check to see if you're logged in by checking if the user ID variable has been set in your session. If you're logged in, we skip the rest of the code and run the current page as normal. If you're not, the logon code is executed.

At this point two things can be happening: either you're entering the page for the first time, in which case we want to generate a login screen, or you've already submitted the login form. By checking to see if the form.login variable exists, we know if you're submitting the login form. If you're logging in, we check the database to verify your login name (your e-mail address) and password; You don't have to use a database to store user names and passwords; you could simply check for a predefined login name and password instead. If your login was valid we set your session.user_id variable. If it was invalid we set an error message. The message tells you only that your login was invalid; it could provide additional information, such as informing you that your login has expired.

The next step of the code checks to see that you're currently logging in or if an error message was generated while logging in. If neither of these is true, you've just completed a successful login and the code is skipped, allowing the rest of the page you're on to execute normally. If you're not logging in or received an error message when logging in, the login form is shown. This login page can easily be changed to match your site. We then check to see if we have an error message. If there's an error, it's displayed in bold red text. Next we generate the login form. For our form action we derive the name of the page we're currently viewing, causing the page to submit back to itself. As part of the form action we also include any variables that we passed in the URL. Next we loop through the special Form.FieldNames list to create hidden form fields for any that we received. Then we display our login and password text boxes, which have been placed in an HTML table to align them nicely. After the page is displayed we use <CFABORT> to stop the template; this prevents the remainder of the page from being processed.

Potential Glitches
There are a few potential problems to look out for when using this model. The first is the possibility of a duplicate field name. The login form that's generated uses a login and password field. If you use the same form field name on one of the pages secured by the script, you'll have a conflict.

Another thing to watch out for are double quotes (the " character) in the form field data. The hidden form fields that pass along the user data use double quotes. When this happens you'll have problems with the HTML and the data won't be passed along correctly. You can eliminate this problem by using a regular expression to encode the double quotes.

More Stories By Kelly Brown

Kelly Brown is the CTO of About Web (www.aboutweb.com), an Internet solutions provider in the Washington, DC, area. He has a BS and MS in computer science and is a Microsoft-certified systems engineer.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.