Hey Charlie, There are a number of ways to implement access controls in CFML depending on your needs. I'm not clear what the scope of your project is or what you're trying to accomplish but I can offer some assistance...
You're going to need a few basic pieces to implement authentication, session management and access control. Assuming you haven't done the authentication piece yet, you'll need the following: 1. A sign-up form and/or admin form for adding users to a user database table so they can later authenticate against the stored information. 1a. A password reset and change password form and functions are also recommended. 1b. System generated random passwords for initial sign-up/adding of users and password resets is strongly recommended. 2. A FORM that gathers the username and password of the user and submit to a processor page (can be the same page) 3. A user database table to store the login information for your clients, something along the lines of: id int auto-increment username varchar(255) not null password varchar(255) not null last_on datetime 3a. NOTE: Use Hash() on your passwords and encrypt passwords and usernames before storing them in the database. Use a javascript Hash() routine on your login form to hash your users passwords before they are sent to the browser. 4. A processor that looks for the (encrypted) username and (hashed and encrypted) password submitted by the user from the user database table 4a. If there is a match, then you kick into session management and access controls 5. Session Management can be handled by the combination of either SESSION scoped variables (be sure to <cflock> them when you set them to prevent race conditions) or a COOKIE and another database table to manage sessions, something along the lines of: id int auto-increment session_id varchar(255) not null user_id varchar(255) not null last_action datetime not null 5a. NOTE: Generate a session id with CreateUUID() or another random pattern generator, encrypt the session id and user id before storing in the database. 5b. Encrypt your encrypted session id (pref using a diff algorithm) and then use that value as either your SESSION scoped variable value or your COOKIE value 6. Application.cfc session management is suggested. This is done by having an OnRequestStart block that, if within a specific path (CGI.PATH_INFO) of the site usually, reads in the SESSION scoped variable or COOKIE on each request, compares the time of the last request to some timeout period you've set as an APPLICATION variable in the Application.cfc and the current time (e.g. if 15 minutes have passed since the last user action on the site, for example) and then either refreshes the session by updating the last_action field in the session database table (if 15 minutes have not passed) or return them to the login page (if 15 minutes have passed) with a 'session timeout' message, and if you're crafty about it, the ability to return the user to the page he was visiting before the session times out. 7. Access Control is a means of limiting already authenticated users to specific areas or specific content on your website. For example, an average CMS site might have authors, content reviewers and moderators each representing different abilities and access to different parts of the average CMS backend. Authors would be able to write and modify articles, content reviewers would be able to write, modify and publish articles and moderators may simply only be able to approve content for publishing, for examples. This type of access control can be implemented in one of two standard ways, as follows: 7a. Roles - you can either add another table to your database to manage the role/user relationship, or you can use a list based approach with a single field added to your users table called roles, either one works and simply depends on preference and code required. In both cases, you have to either have another table the represents the relationship between pages or content on your site and the allowed Roles able to access them - which is handled in a similar way to handling user roles - either as a relationship table (page/role) or as a list of allowed roles referencing one page (page/roles), or can be hard coded into each page you wish to check (e.g. <cfif Find(qGetUser.Roles,'Author')> ... allowed access content </cfif>). 7b. In the event that you wish to assign multiple roles to the same user, there is a mathematical way to handle this which is much quicker than textual Roles and allows for a much smaller footprint in your database. It is, however, slightly more complicated and complex. The easiest way to explain it is with a bit of code I wrote to illustrate that capabilities of using positional math with a single 32-bit byte to assign (up to) 32 roles to a single user with one byte. 64-bit systems running 64-bit CF can also handle 64-bit bytes quickly (32-bit CF can also do 64-bit positional math, but it requires two processor cycles), allowing for up to 64 roles to a single user in a single byte. <!--- Name: using_bit_based_access_control.cfm Author: Denard Springle ( [email protected] ) Description: Demonstrate using binary objects and bit manipulation Created: 05/06/2009 License: Creative Commons Attribution-Non Commercial 3.0 ---> <!--- initialize a string to hold the binary representation of our 32- bit zero byte ---> <cfset zeroByte = ""> <!--- initialize the zero byte ---> <cfset zeroByte = RepeatString('0',32)> <!--- set up a row color variable to alternate colors ---> <cfset rC = 0> <!--- set up a table to output the progress and results of this operation ---> <h1>32 Bit Combinations</h1> <p>The following table represents the 32 bit positions available in a 32-bit byte. By using these positions you can assign up to 32 access control levels to the same user without depending on role lists (i.e. IsUserInRole() style). Storage and processing of a single 32-bit byte is demonstrated here in it's most basic form for easy digestion, however the use of single 32-bit byte is an optimal mathmatic calculation and storage method for tiered access controls.</p> <table cellpadding="2" cellspacing="0" width="50%"> <tr> <th style="text-align:center;">Bit Pos</th> <th style="text-align:center;">Bin Val</th> <th style="text-align:center;">Dec Val</th> <th style="text-align:center;">Hex Val</th> </tr> <!--- set up the first row (of zero's) ---> <tr style="background-color:#FFFFEE;"> <td style="text-align:center;">0</td> <td style="text-align:center;">[ <cfoutput>#zeroByte#</cfoutput> ]</td> <td style="text-align:center;">0</td> <td style="text-align:center;">0</td> </tr> <!--- create a new structure to hold the access controls ---> <cfset thisStruct = StructNew()> <!--- put the zero byte in the structure (for later use) ---> <cfset structInsert(thisStruct, 'this0', zeroByte)> <!--- loop through the 31 assignable bits (e.g. excluding zero [0]) --- > <cfloop from="1" to="31" index="iX"> <!--- initialize a string to hold the binary representation of our 32- bit byte ---> <cfset binaryByte = ""> <!--- set the current column to 32 bits minus the current index of iX, so, bit 31, 30, 29, etc. ---> <cfset thisCol = 32-iX> <!--- loop through the zero bits which make up the beginning (left) of this byte (e.g. thisCol value) ---> <cfloop from="1" to="#thisCol#" index="iY"> <!--- add this bit positions false (0) bit to the byte string ---> <cfset binaryByte = binaryByte & '0'> <!--- loop through the remaining begininng (left) bit positions that are zero ---> </cfloop> <!--- add this bit positions true (1) bit ---> <cfset binaryByte = binaryByte & '1'> <!--- init remaining columns ---> <cfset newCol = 32-(thisCol+1)> <!--- check if we're at the last element in the list ---> <cfif newCol GT 0> <!--- loop through and pad the right with zero (0) ---> <cfloop from="1" to="#newCol#" index="iZ"> <!--- add a zero (1) to the binary string ---> <cfset binaryByte = binaryByte & '0'> <!--- loop through the rest of the padded zero's ---> </cfloop> <!--- end checking if we're at the last element ---> </cfif> <!--- put this byte in the structure (for later use) ---> <cfset structInsert(thisStruct, 'this#iX#', binaryByte)> <cfif rC EQ 0> <cfset rowCol = "##DDDDEE"> <cfset rC = 1> <cfelse> <cfset rowCol = "##FFFFEE"> <cfset rC = 0> </cfif> <!--- output the current bit position and byte values to the screen --- > <cfoutput> <tr style="background-color:#rowCol#;"> <td style="text-align:center;">#iX#</td> <td style="text-align:center;">[#binaryByte#]</td> <td style="text-align:center;">#InputBaseN(binaryByte,2)#</td> <td style="text-align:center;">#FormatBaseN(InputBaseN(binaryByte,2), 16)#</td> </tr> </cfoutput> <!--- loop through the rest of the possible byte values ---> </cfloop> <!--- end the table ---> </table> <br> <br> <!--- dump the structure ---> <h1>The structure</h1> <cfdump var="#thisStruct#"> <br> <br> <h1>The Test Case</h1> <p>In this test case we are going to add existing members of the structure (bytes) together. By adding these bytes together and then converting back to base 2 (binary) output you will see how multiple levels could be assigned to the same user.</p> <!--- create a test case by adding together random bits from the 31 bytes created and stored in the structure ---> <cfset testCase = InputBaseN(structFind(thisStruct, 'this11'),2) + InputBaseN(structFind(thisStruct, 'this16'),2) + InputBaseN(structFind(thisStruct, 'this19'),2) + InputBaseN(structFind(thisStruct, 'this2'),2)> <!--- initialize an output string ---> <cfset testCaseOutput = ""> <!--- loop through the missing begining (left) zero bit's ---> <cfloop from="1" to="#32-Len(FormatBaseN(testCase,2))#" index="iX"> <!--- add the missing zero bits ---> <cfset testCaseOutput = testCaseOutput & '0'> <!--- loop through the rest of the zero bit's ---> </cfloop> <!--- set the output string to the zero's concantenated with the binary output of the test case ---> <cfset testCaseOutput = testCaseOutput & FormatBaseN(testCase,2)> <!--- initalize a role list to capture the role names ---> <cfset roleList = ""> <table cellpadding="2" cellspacing="0"> <tr> <th style="text-align:center;">Test Case Binary</th> <th style="text-align:center;">Test Case Decimal</th> <th style="text-align:center;">Current Bit Binary</th> <th style="text-align:center;">Current Bit Decimal</th> <th style="text-align:center;">Result</th> </tr> <tr style="background-color:#FFDDDD;"> <td style="text-align:center;">[ <cfoutput>#testCaseOutput#</cfoutput> ]</td> <td style="text-align:center;"><cfoutput>#testCase#</cfoutput></td> <td style="text-align:center;">[ <cfoutput>#structFind(thisStruct, 'this0')#</cfoutput> ]</td> <td style="text- align:center;"><cfoutput>#InputBaseN(structFind(thisStruct, 'this0'), 2)#</cfoutput></td> <td style="text-align:center;">False</td> </tr> <!--- loop through the 31 bytes in the structure ---> <cfloop from="1" to="31" index="iX"> <!--- output the current test byte itteration (iX) information ---> <cfoutput> <!--- perform BitAnd against the current byte (iX) and the testCase byte ---> <cfif BitAnd(InputBaseN(structFind(thisStruct, 'this#iX#'), 2),testCase)> <!--- if BitAnd returns true, then the bit represented by the current byte (iX) is present in the testCase byte ---> <tr style="background-color:##BBFFBB;"> <td style="text-align:center; border-left:1px solid ##000000; border- top:1px solid ##000000; border-bottom:1px solid ##000000;">[#testCaseOutput#]</td> <td style="text-align:center; border-top:1px solid ##000000; border- bottom:1px solid ##000000;">#testCase#</td> <td style="text-align:center; border-top:1px solid ##000000; border- bottom:1px solid ##000000;">[#structFind(thisStruct, 'this#iX#')#]</ td> <td style="text-align:center; border-top:1px solid ##000000; border- bottom:1px solid ##000000;">#InputBaseN(structFind(thisStruct, 'this#iX#'),2)#</td> <td style="text-align:center; border-top:1px solid ##000000; border- bottom:1px solid ##000000; border-right:1px solid ##000000;">True</td> </tr> <!--- set the value of this byte in the role list ---> <cfset roleList = ListAppend(roleList,structFind(thisStruct, 'this#iX#'))> <!--- otherwise, BitAnd returned false, so the bit represented by the current byte (iX) is *not* present in the testCase byte ---> <cfelse> <tr style="background-color:##FFDDDD;"> <td style="text-align:center;">[#testCaseOutput#]</td> <td style="text-align:center;">#testCase#</td> <td style="text-align:center;">[#structFind(thisStruct, 'this#iX#')#]</ td> <td style="text-align:center;">#InputBaseN(structFind(thisStruct, 'this#iX#'),2)#</td> <td style="text-align:center;">False</td> </tr> </cfif> <!--- end checking current test byte ---> </cfoutput> <!--- loop through to the next byte ---> </cfloop> </table> <br> <br> <h1>The result</h1> <p>Listed below are the binary roles detected by the BitAnd checking routine.</p> <!--- output the roles randomly picked ---> <cfoutput>#roleList#</cfoutput> This is all, of course, subjective and there are a number of different ways to handle authentication, session management and access control in ColdFusion - this is one way. I never use the <cflogin> functions myself so I'm not sure if they're even supported in OpenBD, but if it is then that is another option for the authentication and session management - access control is still up to one of the two methods I suggested, though IsUserInRole() lends itself to the non-bit based, textual approach which I find to be utterly and painfully slow so I almost always use positional math based access controls for speed. But then almost every application I write is chock full of encryption and decryption so every millisecond I can squeeze out of my apps the better ;) Anyway, I hope this answers your question, and if not, just shoot some more specific feedback on what you're trying to accomplish and I'll see if I can't help more ;) -- Denny On Jan 11, 4:21 pm, Skellington <[email protected]> wrote: > Hello, > I'm working on a new application and I dont want to re-invent the > wheel here. I would like to do access control in my application but > I'm not sure how to handle this? Meaning, do I just create a group in > a database table and add users to and then use "if" statements to do > filtering or is there a cfc or plugin that helps with something like > this? > > Thanks, > Charlie -- Open BlueDragon Public Mailing List http://www.openbluedragon.org/ http://twitter.com/OpenBlueDragon official manual: http://www.openbluedragon.org/manual/ Ready2Run CFML http://www.openbluedragon.org/openbdjam/ mailing list - http://groups.google.com/group/openbd?hl=en
