A while back, a colleague emailed us asking if anyone knew how to get CF Admin to use LDAP for authentication instead of it’s own private data store. It wasn’t a question any of us had any experience trying out, and I was curious, so I did a bit of digging and found something interesting. I’ve been meaning to blog about it for ages, so I’m happy to finally have the chance.
Here’s the deal: the ColdFusion Administrator (at this point) is restricted to using its own datastore, it’s own login code, and it’s own security subsystem. Kind of like the Model-T’s color scheme, you can use any login mechanism you want, as long as it’s the one that comes baked-in. This can be a problem, especially if you want your team to be able to access the administrator via a login scheme like LDAP or a SQL DB full of user/group information and divide up access to different parts of the administrator. Now that the Admin has multi-user capability this is even more important, but the restriction still applies: There’s no built-in mechanism to swap out the datastore that CF Admin uses for users, roles and activities.
That doesn’t mean, however, that you can’t make this work… The key files in the Administrator that have to do with gaining access and setting up the environment are login.cfm and enter.cfm. Login is the form (dur) and it posts to enter.cfm which sets up the environment (including instantiating the whole AdminAPI). After IMing with Ben Forta about it a bit, I was able to come up with something that was, if not perfect, at least a workable solution. You see, while both of those pages are encrypted using cfencrypt, there are no rules against replacing the built-in files with files of your own creation. Well, there’s actually a caveat there: it seems that enter.cfm does a great deal of “stuff” to set up the Administrator’s environment and I just wouldn’t want to replace it without knowing more about what it does first.
The simplest login.cfm code required to gain access to the CF Admin is:
<cfset createObject("component","CFIDE.adminapi.administrator").login("pwd","username") <cflocation url="http://localhost/CFIDE/administrator/index.cfm" addtoken="false" />
Since an uncredentialled user is always forwarded to login.cfm, and since enter.cfm (or whatever file sets up CF Admin’s environment) is run on every request, putting that in login.cfm will essentially remove any sort of login process at all. If you hit any page in the Administrator, you’ll always see it. Try it… change the name of login.cfm to login.cfm.old and put a new login.cfm file containing the above code (with a valid username/password combination, obviously) and hit a page in the Administrator. BOOM! Right on thru. Obviously this isn’t a great idea, but it illustrates the fact that you can use login.cfm as a hook into the front end of logging into the Administrator and replace it with functionality of your design, so long as it ends with adminapi.administrator.login() and forwards back to index.cfm.
Incidentally, this all has to happen within the context of the Admin’s folders… apparently the application scope is involved in figuring out who’s logged in and who isn’t and, therefore, if you call administrator.login() from another application it will NOT gain you access to CF Admin’s UI. So be sure that you’re working with login.cfm and enter.cfm to make this work.
There are a few primary ways I’ve thought of that this could be accomplished that I thought I’d share here:
- Fetch the credentials from your data store along with role/privilege information anduse the AdminAPI to programmatically create an account for them. The advantage here is that since they’re logging via your data store, you can disable their account before they ever get to the admin without having to use CF Admin to do anything.
- Create a set accounts with specific sets of roles and privileges, have your users credentials verified against your datastore and then call adminapi.administrator.login() using the appropriate account for that user’s login.
- Have login.cfm post to itself, analyze the user’s state in the DB, and display various content based on various switches. If, for example, you have a DB with all sorts of users, some of which are allowed into the administrator, a user with a valid account but no access to the admin could be presented with a page that says “You’re not authorized, click here to request access”, etc., all by having login.cfm post to itself. Yeah, the code would have to be old-school, but it works. Hasn’t everyone, at least once, written a data-entry page that posts to itself with at the top of it to handle the POST data?
In any case, there are many ways to deal with this on either end of the login system… you could integrate the AminAPI into a user-management application, you could use a bulk create/update scheduled task, you could… well you could many things. I guess the point is that even with the encrypted code in the Administrator’s directories, there are still ways to tinker with and modify CF Admin’s functionality to get it to do what you want it to.
I am going to end this post with a question: Knowing what you now know, how would you accomplish the task of using an alternative source of credentials for the CF Administrator?