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

Reply via email to