When roles based security was added to ColdFusion MX, I was a pretty big fan of it. Almost all of my open source applications make use of cflogin. Since that time though my relationship with the feature has soured a bit. There were numerous security issues, and I had wished for more out of the box support for basic security features. ColdFusion 8 improves this feature. Read on to find out what has been added - and why I'm still a bit wary of using it.
In previous versions of ColdFusion, your security related tags and functions were limited to:
- cflogin - The primary tag to enable roles based security.
- cfloginuser - The tag that marked you as a logged in user.
- cflogout - Do I have to explain this one?
- GetAuthUser - returned the current user name.
- IsUserInRole - Tells you if a user is in a role. If you pass a list of roles, it checks each one and if you are in all of them, returns true.
So one of the biggest things missing - and added to ColdFusion 8, is IsUserLoggedIn. As you can probably guess, this tells you if a user is logged in or not. For a site where a user has to be logged in, this is probably not so important. But for sites where users optionally log in, you normally need to know if they are currently authenticated or not.
Another new function is GetUserRoles. This returns all the roles a user belongs to. It does not return any roles that may have been defined at a servlet level. (If that seems like Greek to you, then you don't have to worry about it.)
A nice addition is IsUserInAnyRole. This is something I had to add as an UDF to my applications. It allows you to check and see if a user is in any particular role in a list. This is great for sites where you may have logic of: Group X, or Admins, can do Y. The idea being that Group X is the main role you want to check for - but admins are allowed to do anything.
So - I'm happy to see all of this added to feature set. Some of these are direct results of some ERs I filed (or my general complaining). I still have one core problem with this feature. ColdFusion's roles based security system has automatic integration with web server security. What do I mean by that? Imagine you protect a folder on your web server. When the browser requests a page in that folder, you have to authenticate before you can view the page. This is not ColdFusion security. It is security at the web server level. The cflogin tag can integrate with that and automatically pick up the fact that you've authenticated. That is great and all ... but what if you don't want to integrate that level?
Here is a great example of where this fails. (And a real example at that.) Someone deploys BlogCFC to their intranet, which is completely protected at the web server level. However, BlogCFC still needs you to login to write blog articles. But if I were to test isUserLoggedIn, it would return true since I was authenticated at the web server level. There is no way to ignore that level and just check to see if you are authenticated at the application level.
Of course - this is only really a problem for people shipping applications like I do - things that are placed inside other web sites. If you were building the entire web site, you know if web server security will be used or not.
I'm still hoping a future release will allow us to "decouple" from the web server!
Archived Comments
I see your point but instead of removing or decoupling, I'd like to see it as an optional setting. Maybe at the application level, useWWWAuth or something.
My reason is I like having IIS handle the auth for some of my apps. Support for password policies and such are supported at the OS level, I don't have to build it in to the application.
Yep, that is what I meant - but I certainly didn't say it right. I can see the feature being useful.
Personally I wouldn't just check for isLoggedIn for something like posting to a blog. Even if the only person logging in was the blog owner, I'd still give them an "admin" role to check against instead.
It just doesn't feel right to me to only check if they're logged in and not worry about who they are, and I guess this kind of situation is where that paranoia makes sense :)
RE your example:
Couldn't you turn to Roles to help you with this problem? What you're talking about is really authorization (authZ), not authentication(authN) anyway. In your example, the person has already presented their credentials and been accepted as who they say they are. Whether those credentials allow them access to specific functionality (BlogCFC) is another matter. Define a BlogCFC_User Role. If isUserInRole('BlogCFC_User') returns false, no dice.
Now if your webserver authN does do any authZ in the container, maybe you want to do a lookup based on the authenticated username on their first hit and setup your own authorizations.
You do not have to call cfloginuser from inside of cflogin, so you could setup you own roles in that way even if the user is authenticated. However, I have to test and see what this would do to previously existing roles. My first guess is that it would wipe them, so you'd probably want to check them first and append them to whatever you were doing. Note that calling cfloginuser outside of cflogin will turn the user into an 'authenticated' one (isUserLoggedIn will return YES), so you'd have to kind of do an anti-CFLogin to make sure it isn't run in this way (to add Roles) UNLESS the user is already logged in.
Does that muddy the issue enough?
I beg to differ. In the situation I provided, the user did not present their credentials. Or to be more clear - they presented their credentials to the web server, not to the application. The web server said, "You must authenticate before you view any of my files,", but BlogCFC needs a different authentication for its own system. Even if I did use roles, I still need a way to _set_ the roles. I do it now in cflogin, which will never run since you logged in at the web server level and cflogin thinks your already authenticated.
@Raymond:
This is obviously a hack (and the issue does seem like oversite to me and would cause us issues as well,) but couldn't you check to see if a Session Login variable exists and if it doesn't, run CFLOGOUT tag?
That way you'd clear the knowledge of the Web Server Authentication and could then run the CFLOGIN.
Just an idea.
It does seem like there should be a way to specify what kind of CFLOGIN authentication should be used--maybe per CFAPPLICATION (i.e. All, CF-only, Web-server only, etc.)
I'm kind adoing that now. My isAuthenticated checks for a session variable. I don't check getAuthUser().
@Ray
I think you mean BlogCFC _wants_ its own authentication. If the person who installed the app did so in a directory protected by webserver-based authN then I would assume that they a) did that on purpose and b)they would probably like to have one credential store/login. The webserver has validated the enduser's identity (which the installer told it to do)- why does BlogCFC _need_ to do that again? Granted, it is easier for the app to do it that way, but it is not a requirement.
As my previous post mentioned, you don't have to call cfloginuser from inside cflogin, so you do have a way to set the roles, but it would require you changing your use of cflogin.
I think as more people try to integrate applications like BlogCFC into their systems, we will see a greater need for a pattern in which applications are able to expose their authorization schema to the enclosing system and make use if its authentication. Intranets are becoming notorious for forcing users to login repeatedly (even where they use LDAP or Active Directory to ensure one user/one credential).
@Ray
I think you mean BlogCFC _wants_ its own authentication. If the person who installed the app did so in a directory protected by webserver-based authN then I would assume that they a) did that on purpose and b)they would probably like to have one credential store/login. The webserver has validated the enduser's identity (which the installer told it to do)- why does BlogCFC _need_ to do that again? Granted, it is easier for the app to do it that way, but it is not a requirement.
As my previous post mentioned, you don't have to call cfloginuser from inside cflogin, so you do have a way to set the roles, but it would require you changing your use of cflogin.
I think as more people try to integrate applications like BlogCFC into their systems, we will see a greater need for a pattern in which applications are able to expose their authorization schema to the enclosing system and make use if its authentication. Intranets are becoming notorious for forcing users to login repeatedly (even where they use LDAP or Active Directory to ensure one user/one credential).
Ray, a five year old post but still very helpful! Thank you! I was wondering why my cflogin stuff wasn't firing. We use a common third party authentication app across a number of sites and servers that sets cgi.remote_user. I was trying to look for it and then sort of transfer over to cflogin for a particular app. The app kept skipping this and yet both IsUserLoggedIn and getAuthUser made it appear my cflogin had run when it hadn't. Now I know why! Thanks again.
Glad to help.