Login and Logout Flex Example That Uses ColdFusion CFLogin and CFC Role Security
This example of using Flex to login/logout users and specify user roles in combination with ColdFusion's CFLogin tag on the backend is based on work done by Ray Camden (see: http://ray.camdenfamily.com/index.cfm/2006/11/25/Last-build-of-my-Flex-2ColdFusion-Security-Homework) and includes material provided in comments to Ray's blog entry by Todd Sharp and Kevin Schmidt.
The goal of this example is to allow users to login to a Flex application and after the user has successfully logged in for the Flex application to provide functionality based on the user's role. The application uses CFLogin on the backend to check the user's login information and log the user in. CFLoginUser allows you to set a role for the logged in user that CF can then check before running a CFC function with roles specified. Our Flex application can send the login credentials each time we call a CFC function. CF can use those credentials (username/password) to ensure the caller has the role that is allowed to call the CFC function.
For a working example see: http://www.brucephillips.name/flex/loginwithroles/bin/loginwithroles.html (right click to view the source code).
If the user logs in with admin for username and admin for password, CF logs the person in (see function loginUser in the CFC) and sets that person's role to admin. The Flex application this user has logged into can now call any CFC's with a role of admin.
If the user logs in with user for username and user for password, CF logs the person in and sets that person's role to user. The Flex application this user has logged into can now call any CFC's with the role of user, but not with the role of admin.
Here are my references used in creating this application in addition to the Ray's blog entries (see above).
ViewStack - Flex 2.0 Developer's Guide, Chapter 16, Using Navigation Containers
mx:RemoteObject (specifically review method setRemoteCredentials)
Using ColdFusion MX With Flex 2 Adobe (I cannot find where to download this PDF now, I got it back when Flex 2 was still in Adobe Labs)
When you first load the Flex application, you see the login view. The login view includes a form where the user can enter a username and a password. It also shows 3 buttons: login, Get Secure Admin Data, and Get Secure User Data. The login button is disabled until the user enters text in the username and password form fields (this is from Todd Sharp, see comments on Ray's blog entry).
The other two buttons are there just to demonstrate that until the user logs in and has been given a role, the CFC functions those buttons call when clicked will just return an error message stating that the current user is not authorized to invoke this method.
After the user provides a username and password and clicks on the login button, the Flex method logIn is called.
private function logIn():void{
cf.setRemoteCredentials(username.text, password.text);
cf.loginuser();
}
In this method I call the mx:RemoteObject (named cf) setRemoteCredential's method and pass it the values entered in username and password. Now whenever the Flex app uses this RemoteObject to call a CFC function, Flex will pass the username and password in a manner that CF's CFLogin will recognize them.
If you examine the CFC function loginUser (see below), you will see that I'm using CF tags CFLogin and CFLoginUser. Consult the reference links above if you need more information about what these tags do. Because I've used setRemoteCredentials on my RemoteObject, the CFlogin.name and CFLogin.password are available and can be referred to inside the CFLogin tag. If the CFLogin values provided match my hard-coded values (either admin/admin or user/user) then I use CFLoginUser to log the user in and set the user's role. CFLoginUser creates by default a cookie in memory that now identifies this user and his role. Now whenever this user calls a CFC function where the role attribute is specified, CF can check to ensure that the user has that role.
<cffunction name="loginuser" access="remote" returntype="struct">
<cfset var person = StructNew()>
<cfset person.login = "false">
<cfset person.name = "none">
<cfset person.role= "none">
<cflogin idletimeout="180"> <!---user will be logged out automatically after 3 minutes of inactivity--->
<cfif isDefined("cflogin.name") AND isDefined("cflogin.password")>
<cfif cflogin.name EQ "admin" AND cflogin.password EQ "admin">
<cfloginuser name="#cflogin.name#" password="#cflogin.password#"
roles="admin">
<cfset person.login = "true">
<cfset person.role = "admin">
</cfif>
<cfif cflogin.name EQ "user" AND cflogin.password EQ "user">
<cfloginuser name="#cflogin.name#" password="#cflogin.password#"
roles="user">
<cfset person.login = "true">
<cfset person.role = "user">
</cfif>
<cfif person.login EQ "true">
<cfset person.name = getPersonName(cflogin.name, cflogin.password)>
</cfif>
</cfif>
</cflogin>
<cfreturn person>
</cffunction>
Note also that the loginUser CFC function returns a structure back to Flex. This structure just includes the login result (the string "true" or "false"), the person's name, and the person' s role.
Back in the Flex application, function loginResult receives the structure, converts into to a generic Object, and assigns it to my Object named person. If the value of the LOGIN field in the person object equals "true", I change the view that is visible in the ViewStack to the secure view.
If you examine the secure view, you will see where I use some logic to determine which text to show on the label (Secure User Area or Secure Admin Area) and also based on the person.ROLE value whether or not to make a button visible. For example if the person.ROLE is "user", then the Get Secure Admin Data button will not be visible. Though even if the button were visible and the user clicked on it, he would just get back an error message since the CFC function called when that button is clicked can only be called by users with the admin role.
After the user is logged in, he can click on a logout button. This calls Flex function logOut, where I call the CFC function logoutUser, which uses CFLogout to remove "knowledge of the user ID, password, and roles from the server. If you do not use this tag, the user is automatically logged out when the session ends."
The Flex function logoutResult executes automatically when the CFC function logoutUser returns. In this Flex logoutResult function I set the remote credentials to null and change the view that is visible back to the loginView.
One area that I need to research further is the security of the username and password passed as part of the RemoteObject's call to the CFC function. I don't know if this is encrypted or in plain text and if the RemoteObject call could be easily intercepted. If you have any information about security, RemoteObject, and setRemoteCredentials please post a comment.
Thanks again to Ray Camden and his excellent blog.


I don't think your analysis is correct. I believe you don't need to use CFLogin for each CFC. All you would need to do is setRemoteCredentials for each RemoteObject to the correct username and password.
CFLoginUser logs the user's information in a memory cookie. If the user's role is in a role attribute value for any CFC function (not just the CFC function that is in the same CFC as where CFLoginUser occurred) then the user can execute that CFC function.
If you have setRemoteCredentials for the RemoteObject in Flex, when Flex calls a CFC's function, it sends that information in the request. CF takes that information, sees if there is a cookie with the unique identifier matching the username and password, and if there is a cookie gets the role for that user.
When I have a chance I will test this theory by putting the methods that get secure data and have the role attribute in a separate CFC from the CFC that contains the loginUser function (where CFLogin and CFLoginUser are used).
Bruce
I tested using multiple CFCs and what I noted above is correct. For each RemoteObject in Flex, you just setRemoteCredentials to the username and password.
Bruce
I've tested your application and it's nice.
However, if a user neglects using the logout button and for instance simply closes the browser and then tries to login again they will get the "Authentication failed" alerter and the "Get secure admin data" button will still be functioning.
I'm new to both ColdFusion and Flex so I wasnt able to figure this one out myself. How do I correct this?
Thanks!
//Morgan
I"ll have to run some tests with the use case you described. I've not used this login system in a production application. Unfortunately, I"m buried at work for the rest of the week, but may be able to take a look at the issue this weekend.
Thanks for letting me know about the issue.
Apparently the problem you describe is a known issue with CFLogin. If the user doesn't use the logout process, causing the <cflogout> to run, but just closes the browser, the authentication information is still available on the server until the timeout session is reached (which in my example is 3 minutes).
See: http://cfdj.sys-con.com/read/46356.htm
and google cflogout close browser for related items.
The example I used for this blog entry was primarily to test using role-based security. For a Flex application you can control what CFC functions are called in your ActionScript code. So role-based security isn't necessary.
Instead of using cflogin and cflogout to login/logout users you could just use a CFC function that checks the parameters provided by Flex against a database. If they are correct log that user in and then change the viewStack to the appropriate child. If the user clicks on the logout button in flex, just change the viewStack to the login screen child.
Remember, you can set your CFC functions access attribute to public instead of remote, so only the Flex application running on your server can access the CFC functions. You don't need to use remote when both the Flex app and the CFC are on the same server.
the error is the following:
(mx.rpc::Fault)#0
errorID = 0
faultCode = "Client.Error.MessageSend"
faultDetail = "Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 404: url: 'http://localhost:8500/flex2gateway/'"
faultString = "Send failed"
message = "faultCode:Client.Error.MessageSend faultString:'Send failed' faultDetail:'Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 404: url: 'http://localhost:8500/flex2gateway/''"
name = "Error"
rootCause = (Object)#1
code = "NetConnection.Call.Failed"
description = "HTTP: Status 404"
details = "http://localhost:8500/flex2gateway/"" target="_blank">http://localhost:8500/flex2gateway/"
level = "error"
i don't know why is searching http://localhost:8500/flex2gateway...that directory does not exist...
Other question...i need to modify the service-config.mxml for use remote objects?
I really aprecciate your help because in spanish the help is null
Also are you using CF version 7.02 or higher?
what is happening?
http://www.adobe.com/support/coldfusion/downloads_...
Thank you again!!!
Alex