OCCASIONAL CF NEWSLETTER
Well, it's been a while! Welcome to our new subscribers. I've been writing a book on ColdFusion to be published by Prentice Hall in February of next year. Here is a sneak preview...
1. Securing the Application
Many of us use a simple login procedure to ensure that only validated users can use our application. Often, this is done by having a database of users. When a user logs in, the user name and password they enter is checked against the database. If a match occurs, a "tag" of some sort is affixed to the user . Often, the tag is either a cookie, a session variable, or a client variable. When I implement this, I usually make the tag name something like "isValidated" and I set it to "TRUE". In my code, checking for validation makes for the very readable
<cfif client.isValidated>.
[Note: This article is Fusebox-specific. The technique is universal.]
Here's a different way of handling securing an application. It provides lots of flexibility with minimal fuss -- thanks to BitAnd(), a handy but obscure CF function.
Begin by assigning a numeric value to a specific permission. The permission can be "horizontal", spanning multiple fuseboxes/fuseactions (such as "edit" or "delete") or you may find it more useful to assign permissions for specific fuseboxes, such as Administrator or SalesPerson. The value you assign should be a unique member of the set of values obtained by taking 2 to 0 power (or 1) through 2 to the 32 power.
For example, you might decide to assign the value of 2 to the 1st power (or 2) as the needed permission for using the SalesPerson fusebox and a value of 2 squared (or 4) for using the Inventory fusebox and a value of 2 cubed (or 8) for even more advanced features. You don't need to think of these permission levels hierarchically-in other words, having permission to a feature with a required access level of 8 does not necessarily give you permission for access levels of 4 or 2.
Here are the permission levels needed for the fuseboxes that make up the Books by Hal application.
Fusebox Permission Required
Main 1
Sales 2
Inventory 4
System 8
Users must also have their own permission levels. These are obtained by adding the values of the permissions you want them to have. If you want to give an inventory clerk permission to use the main fusebox and the inventory fusebox, you add their two values together:1 + 4 = 5.
You can make this easier to read if you set permission levels to variable names. In other programming languages, you would probably set this to a global constant, rather than a variable, but since ColdFusion doesn't have these, you can achieve much the same effect by setting them to a variable that has broad scope.
<cfset Application.mainAccess = "1">
<cfset Application.salesAccess = "2">
<cfset Application.inventoryAccess = "4">
<cfset Application.systemAccess = "8">
These access levels will be set in the Main fusebox's myGlobals.cfm file so that they are available throughout the application.
When the user logs into the system, I set a persistent variable to the value of their permission level. Now, to easily see if a user has the required permission, I use the ColdFusion function BitAnd().
<cfif NOT BitAnd(userPermission,neededPermission)>
<cflocation url="#self#?fuseaction=#request.denied#">
</cfif>
Where you put this code depends on the level of granularity you need for permissions. If you want a fine level of control, you can place this code in an individual fuse. If you are restricting access at the fusebox level, you can place this is the myGlobals.cfm page of the relevant fusebox.
Here's a table showing how BitAnd() interprets a few example values for userPermission and neededPermission.
userPermission neededPermission Result
TRUE
TRUE
FALSE
FALSE
How does this magic work? Let's take the first case, where userPermission is 13 and the neededPermission is 8. As I mentioned, it's not a matter of asking if the userPermission is greater than the neededPermission. Instead, we need to know if the value of the neededPermission is "part of" the userPermission value.
It turns out that there is only one possible combination of neededPermissions that will produce a particular userPermission. So a neededPermission being "part of" a userPermission means that it is one of the numbers in that unique combination. Look at the first few numbers in the sequence:
(Partial sequence of the powers of 2)
The only possible way to come up with 13, the userPermission, is by adding 8+4+1. So 8, the needPermission, is "part of" the userPermission. The really great thing is that the BitAnd() function handles this for you-all you need do is supply the value for a user permission and one for a required permission. Just be aware that the BitAnd() function is a 32-bit function, so you can have only 32 unique permissions.
2. Persistent Variables
Most variables in ColdFusion-what we might call everyday variables-can only be seen by the page they were created on and any pages cfincluded. Once that page (or more accurately, a specific HTTP request) is done, the variable fades back into obscurity.
For the most part, this is what we want our variables to do. It would be inconvenient and inefficient if variables hung about interminably. It would also violate the principle of modularity, so all in all, it's just as well that variables have such a transient existence. Sometimes, though, we want variables to persist for more than the lifetime of a single page. And while most variables are local to the page that created them, sometimes variables need to be visible to everyone.
ColdFusion has different types of variables that do different sorts of work. The common variables-the ones you create with cfset-belong to a structure called variables.[Footnote: You can do everything to the variables structure that you can with any structure, including looping over the structure.]
Other variables can be seen by everyone-the variable CGI.HTTP_REFERER, for instance. Then, there are session variables, client variables, application and server variables, CGI variables, request variables, and cookies. Of course, every one has its own peculiarities that make it idea for one situation, less than ideal for another. Part of their peculiarity arises from the fact that variables grew like topsy, with new variable types added with new releases of ColdFusion as a new need was discovered.
The result of all this is that most people are confused about ColdFusion variables, especially persistent variables-the kind that live on after a new HTTP request is made. I'm going to try to help you sort this out. [Footnote: What follows is far from being an encyclopedic survey of persistent variables. Such comprehensive lists are valuable and are available both in the ColdFusion documentation and in other books on ColdFusion. But I find myself wishing that the author would give us more than a litany of the properties of each one; I think we want to gain insight into how fellow developers approach problems. As Judith Martin ("Miss Manners") pointed out, "If written directions alone would suffice, libraries wouldn't need to have the rest of the universities attached."]
In ColdFusion, you have your choice of the following persistent variables: server, application, client, session, and cookies .
Server and Application variables
Server and Application variables are the most universal in scope-they are accessible to anyone on your server and anyone using your application, respectively. These are good stand-ins for true constants, something that ColdFusion doesn't have. When I use these, I set them once and then don't change them throughout the application.
You need to be aware of a potential problem when using memory-based persistent variables-that is server, application and session variables. These variables can become corrupted when different users attempt to write to them. In fact, the problem can occur when there is only one user, as an individual browser may have multiple connections to the server.
In order to solve this problem, you need to use the <cflock> tag to wrap all reads and writes of memory-based persistent variables. Locks can be either exclusive or read-only. Exclusive type locks restrict all access to the variable to a single request, while read-only allows multiple requests-so long as the request types are reads. Read-onlys work fine if you're using server or application variables as constants, but if there's any chance that someone is going to be writing to these, exclusive locks are safer.
You need to provide a timeout value (how long the lock should hold before timing out). You must also provide a scope for the lock. In ColdFusion 4.5, you simply give it the name of the type of variable you're accessing-session, application, or server. If you're working in a version prior to 4.5, the scope property doesn't exist; instead, you need to provide unique values for the name property. Application and server can be given generic names. Session variables, by dint of their client-based nature, require a unique name for each user. You can use session.SessionID as the name for session variables.
<cflock
timeout="timeout in seconds "
scope="Application" or "Server" or "Session"
name="lockname"
throwontimeout="Yes/No"
type= "ReadOnly/Exclusive ">
</cflock>
Session and Client Variables
For variables that are wed to a specific user and a specific session, you can select either a session or a client variable. Client variables, since they are not memory-based [Footnote: They are stored in the registry (by default),in a database or in a cookie.], require no locking. That's the good news; the bad news is that they cannot, without some special handling, accommodate complex variables such as query results, arrays and structures.
Both client and session variables time out after a period of no requests from the server. The values for both these are settable in the ColdFusion administrator. These values set an upper limit for the timeout-you can lower these when you set the actual variables.
Computers are incorporated in modern ice cream vending machines to enhance their functionality. Ice Cream Vending machines are manufactured by many companies. Your competition will try to overcome all requests for high-tech ice cream vending machines and credit card acceptors
|
|
So, should you use client or session variables? For ease of use, session variables are hard to beat (just remember to use cflock!). The ability to store complex variables natively is very helpful [Footnote: This extends to Application and Server variables that can also store complex data types (query results, structures, etc.)] and if your application isn't going to be hammered by lots and lots of use, I think session variables are a good choice. Still, I find myself using client variables more often. They scale better and being able to store them in cookies or in a database appeals to me. Also, if you have any suspicion that your application might sit on a cluster at some point, I would immediately go with client variables. Session variables in a clustered environment have multiple problems-and problems are what we don't need in programming.
Cookies
Cookies are little text files that sit on the user's machine. They are often used for such things as auto-login-where you want to recognize the user every time he or she comes back to the site. I use cookies when I want long-term "recognizability" and where security is not the utmost concern, as any user who has access to the machine will be seen as the original user. One of the most frequent questions on the ColdFusion forums (forums.allaire.com) concerns the "feature/bug" of ColdFusion that occurs when cfcookie is used on the same page as cflocation. In that case, no cookie will ever be set. I offer two solutions for this:
Javascript version
<script language="javascript">
document.location.href = "someOtherFile.cfm "
</script>
ColdFusion-only version
<cfheader name="Refresh" value="0; url=someOtherFile.cfm">
Contrary to some of the news media, cookies do not consititute a grave threat to national security. They were not created by Bill Gates to spy on innocent users. However, mere facts may not sway your users, who may insist on not allowing cookies. Even if you don't plan on using cookies yourself, this still makes for a major problem, as ColdFusion uses cookies to anchor client and session variables to a specific machine. There is a way to get around this, but it's ugly, requiring you to pass two variables (CFID and CFTOKEN) with every ColdFusion server request. My advice is to not to try to convince your users that there is no nefarious plot to spy on them-instead explain that resistance is futile and that turning off cookies will only anger "them". It's worth a try
Request variables
Finally, you might want to consider the request scope. This isn't a persistent variable-it dies with a new page request-but it does provide for a global scope, and that's sometimes what we're after when we use persistent variables. Request variables can be seen throughout the scope of an http request-including custom tags, making it a very handy variable type when you need a global scope but a short lifetime.
Hope you found something of value in this one. If anyone would like to contribute and win fame and immortality--or at least a mention in the newsletter!--drop me a line at hal.helms
|