I spent two days waiting to see if anybody would respond to my call for "code donations" regarding adding real security to canvasWiki, but no code came flying my way. Of course, in that time I could have just written my own, but I was being lazy. I did end up having to do it myself, though, so thought I'd share in case it saves someone else time later.
My security is based on a user having n roles. Since canvas is hard coded for sysop, admin, user, and all (via the "RoleList" parameter in the CanvasConfig bean in Coldspring.xml) those are the roles I used as well.
Table scripts (mysql):
user table
CREATE TABLE `user` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(35) NOT NULL,
`lastname` varchar(35) NOT NULL,
`username` varchar(35) NOT NULL,
`password` varchar(35) NOT NULL,
PRIMARY KEY (`userid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
INSERT INTO `user` (`userid`, `firstname`, `lastname`, `username`, `password`) VALUES
(1, 'doug', 'boude', 'dougboude', 'mamamiarocks'),
(2, 'suzy', 'queue', 'squeue', 'ihearthuckabees');
roles table
CREATE TABLE `roles` (
`roleid` int(11) NOT NULL AUTO_INCREMENT,
`rolename` varchar(35) NOT NULL,
`description` varchar(75) DEFAULT NULL,
PRIMARY KEY (`roleid`)) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `roles` (`roleid`, `rolename`, `description`) VALUES
(1, 'sysop', NULL),
(2, 'admin', NULL),
(3, 'user', NULL);
junction table
CREATE TABLE `jctuserrole` (
`userid` int(11) NOT NULL,
`roleid` int(11) NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `jctuserrole` (`userid`, `roleid`) VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 3);
MY version of the model/UserRecord.cfc's "login" method:
<cffunction name="login" access="public" hint="I log this user into the site" output="false" returntype="boolean">
<!--- make this do some type of real authentication if desired--->
<!--- you can find the plain-text passwords that match these users in the load() function --->
<cfquery name="getUser" datasource="glock">
SELECT r.userid, r.firstname, r.lastname, GROUP_CONCAT( rr.rolename ) AS roles
FROM user r
INNER JOIN jctuserrole j ON j.userid = r.userid
INNER JOIN roles rr ON rr.roleid = j.roleid
WHERE r.username = <cfqueryparam value="#getUserName()#" cfsqltype="cf_sql_varchar" />
AND r.password = <cfqueryparam value="#getPassword()#" cfsqltype="cf_sql_varchar" />
GROUP BY r.userid, r.firstname, r.lastname
</cfquery>
<cfif getUser.recordcount eq 1>
<cfset setFirstName(getUser.firstname) />
<cfset setLastName(getUser.lastname) />
<cfset setUniqueId(getUser.userid) />
<cfset setRoles(getUser.roles) />
<cfset setIsLoggedIn(true) />
</cfif>
<cfreturn getIsLoggedIn() />
</cffunction>
(note: Notice my sweet usage of MySQL's awesome "GROUP_CONCAT" function! Turns that field's values into a list...EXACTLY what we need!)
Besides having the above, you also have to set all of the security type parameters in the Canvasconfig bean of Coldspring.xml appropriately to enforce security. They're self-explanatory.
That's it!
Beyond that, I did make a minor tweek to views/dsp.navigation.cfm and views/layout.main.cfm in order to display my user's name and to make the logout link more prominent.
dsp.navigation.cfm change:
just after line 20 ("<div id="navcontainer">"), added this short if statement:
<cfif UserRecord.getIsLoggedIn()>
Logged in as:<br><cfoutput>#UserRecord.getFirstName()# #UserRecord.getLastName()#<br>Roles: #UserRecord.getRoles()#</cfoutput>
</cfif>
layout.main.cfm
Just after line 31 ("<a href="#webpath#/index.cfm">#appTitle#</a>"), added this short if statement:
<cfif UserRecord.getIsLoggedIn()>
<cfoutput>
welcome #UserRecord.getFirstName()# #UserRecord.getLastName()#!
<div style="width:90%;text-align:right;"><a href="#webpath#/index.cfm?event=logout" style="font-size:16px;font-style:italic;">Logout</a></div>
</cfoutput>
</cfif>