Coldfusion global user object - coldfusion

I am trying to set a coldfusion user object for each person as they log in. Similar to how rails has devise and I can call current_user.id or current_user.username from wherever I am in the site. I have a users table that stores roles and other user information. I want to query that and assign all of the fields to a sort of global user object. I can then use that for components, page display etc.
I am trying to figure out where and how to do this. I have tried initializing a component like this in onsessionstart, onrequeststart etc, but when I try to reference globalUser.id in a component for instance it hits a 500 error because globalUser is not defined.
<cfset globalUser = CreateObject( "component",
"controllers.user" ).globalUser(empidname= '#getauthuser()#') />
Any recommended ways to do this? Any plugins that provide functionality like this?

You want to use session variables.
<cffunction name="onSessionStart">
<cfset session.globalUser = CreateObject( "component",
"controllers.user" ).globalUser(empidname= '#getauthuser()#') />
...
</cffunction>
In order for sessions to be enabled, you have to alter application.cfc
component {
this.name = "AppName";
this.sessionManagement = true;

Related

How to set and check session in Coldfusion 11?

I am very new to ColdFusion. I am building a very basic system in which I now need to set a session variable, in case of successful login. But I don't know how to set session in ColdFusion or how to check it on application pages.
I searched for solution but could not find satisfactory solution. I need some example in which a session is set in case of login, and destroyed on logout.
I've read about Application.cfm, but where this file is located?
This could be a simple question and may be repeating in some ways.
Thanks.
First of all you should probably use:
Application.cfc
You can either use:
OnSessionStart
In which case you don't need to lock your session variables, as Coldfusion takes care of this.
If you set your session variable outside of this method, you may need to lock the variable like:
Before login:
<cfif NOT StructKeyExists(session,"authenticated")>
<cflock scope="session" timeout="30" type="exclusive">
<cfset session.authenticated = false />
</cflock>
</cfif>
New account creation:
When a user logs in, remember to use something like BCrypt() to hash the password & store in DB. Don't encrypt passwords as these can be unencrypted and this can create a potential security loophole.
https://github.com/tonyjunkes/BCryptCFC
<cfset salt = BCrypt.genSalt()>
<cfset hash = BCrypt.hashString("password", salt)>
Login validation:
After a user has logged in, use BCrypt() to check whether the clear text password matches the password hash in your DB:
<cfset BCrypt.checkString("password", hash)>
Also check that the 'username' [e-mail] matches...
If BCrypt() validation is successful, then set your 'session' variable:
<cflock scope="session" timeout="30" type="exclusive">
<cfset session.authenticated = true />
</cflock>
This is a very basic implementation of how the login should work, but it gives you an idea of how to get started.
Another tip, is that, if you are locking your 'session' variables, then instead of having to continually use:
<cflock>
When reading from the session, it would be advisable to convert your 'sesssion' variable into the 'variables' scope, like:
<cflock scope="session" timeout="10" type="readOnly">
<cfset variables.lckauthenticated = session.authenticated />
</cflock>
You can then use:
variables.lckauthenticated
Outside of the <cflock> tag.
Now, there is some debate as to whether you need to lock 'session' variables, but my rule, and one that is recommended in Adobe's Official Documentation, is to lock 'session' variables, if you are reading & writing to them outside of onSessionStart.
Then, when your user logs out, just set:
<cflock scope="session" timeout="30" type="exclusive">
<cfset session.authenticated = false />
</cflock>
You can then use this flag, to determine what is displayed to your user.
I usually set several 'session' variables during a successful login, like:
session.userid
session.roleid
There are other things like 'session' rotation, which help to safeguard your session, but these are more advanced topics for another post...

Exempting Coldfusion page from authentication

I need to post from a non-secure CF page to a secure CF page. I don't want to have to go through and implement the user authentication on the page sending the values because its a rather cumbersome process due to the way this legacy site was setup and secondly because the page sending the values is acting as a service between two unrelated order management systems as opposed to a user.
Right now, when I try to post to, the response result is a redirect to the login of the homepage. Is there a way to make an exception for a posting or receiving page from forcing user authentication?
I'm using <cfhttp> to post the values to post page which has a series of <cfparam>'s that I'm passing the values to. Once I pass those values into the post page is when the post page triggers a redirect to the home page because the post page is an internal page in the order management system and is displayed as a client logs in and a session is created for them.
Since you did not provide any code, here is a guess what it might look like and how you could add an exception for specific requests:
<cffunction name="onRequestStart" access="public" output="false" returnType="boolean">
<cfargument name="targetPage" type="string" required="true">
<!--- treat initialized SESSION or matching request token (rtoken) as successful authentication --->
<cfset LOCAL.isAuthenticated = (
isDefined("SESSION.userID")
or
( structKeyExists(FORM, "rtoken") and (FORM["rtoken"] eq "some-secret-only-you-know") )
)>
<cfif LOCAL.isAuthenticated>
<!--- do something... --->
<!--- not authenticated --->
<cfelse>
<!--- redirect to login --->
<cflocation url="login.cfm" statusCode="303" addToken="false">
</cfif>
</cffunction>
Now you could simple add the key-value-pair rtoken=some-secret-only-you-know (i.e. <input type="hidden" name="rtoken" value="some-secret-only-you-know" />) to your POST to bypass the session based authentification.
Disclaimer: Only use this method if the POST parameters (form fields) are not public/editable by the user.
Feel free to provide actual context so I can assist in a more concrete way.
I have written a couple of apps with similar, but not identical requirements. Here is how I handled those requirements in the last one I wrote. All this code is the Application.cfc file in the methods specified.
In onApplicationStart:
application.securityNotNeededPages =
"somePage.cfm,someOtherPage.cfm,someMorePages.cfm";
In onRequestStart
var ThisPage = listlast(cgi.PATH_INFO, "/");
...
if (ListFindNoCase(application.securityNotNeededPages, ThisPage) is false) {
security related code
}
else {
code for when the page does not to be secured
}

Setting session variables with JavaScript in ColdFusion

I have a website with multiple tabs. Each tab runs a separate report based on a set of filters that take their values from session variables.
How things work now:
While the user is inside a report tab they can open a filter menu to select the options that they need to run their report (doctor names, locations, date, etc) and then they can hit the run button to get their report. When the user clicks "run" the form is saving the variables inside the session where they are available to run other reports without having to click "run" or define them again and again.
What I am trying to do:
Instead of having only a "run" button inside the form I need an "Apply" button that will set the session variables from the form without running the current report. This way the user can pre-define their variables without being forced to run a report they don't need.
I tried using ajax that calls a function outside my application which is setting up variables based on the user's selection.
My challenge is to get those variables back from the function in some format where I could use them in updating the current session variables.
This is a sample of my code:
The Apply button:
Apply
My Ajax Function:
function setSession(){
var formData = $('form').serialize();
$.ajax({
url:'/mod_example/components/exampleCFCs/xUtility.cfc?method=setSessionVariables',
data: formData
});
};
And part of my function:
<cfcomponent output="no">
<cffunction name="setSessionVariables" access="remote" returntype="any">
<cfargument name="docid" type="string" required="no">
<cfif isDefined('docid')>
<cfset session.doctorids = docid>
</cfif>
<cfif isDefined('docid')>
<cfreturn session.doctorids>
<cfelse>
<cfreturn 0>
</cfif>
</cffunction>
</cfcomponent>
What I need is to get the value of session.doctorids to be able to update my session variables with the new value.
It sounds like you have this utility cfc in a shared directory and you are calling it directly. As you've noticed, the problem with that is that you end up with multiple sessions. You can get around this issue be setting up a Facade cfc within your application and make your ajax calls to that cfc.
If you only want to expose the setSessionVariables then you could use this cfc:
<cfcomponent output="no">
<cffunction name="setSessionVariables" access="remote" returntype="any">
<cfset var xUtility = createObject('component','mod_example.components.exampleCFCs.xUtility')>
<cfreturn xUtility.setSessionVariables(argumentCollection=ARGUMENTS)>
</cffunction>
</cfcomponent>
If you want to expose all methods of the utility cfc, then you can extend it:
<cfcomponent output="no" extends="mod_example.components.exampleCFCs.xUtility">
</cfcomponent>
This would allow you to call methods on the utility cfc while maintaining a single session scope (per user of course).
EDIT:
Been a while since i've worked in wheels...but i remember not liking AJAX in the wheels framework. If you create a new subfolder and call it 'remoting' and put the facade in there, and drop an application.cfc in there that looks like this:
<cfcomponent >
<cfset this.name = 'whatever_your_wheels_app_name_is'>
<cfset this.SessionManagement=true>
</cfcomponent>
You should be able to use that facade and this application.cfc will piggyback on the existing application with the same name. The problem with this approach would be if the application times out, and a remote call is the first request to the application, then the wheels application scope might not get set up properly.
It would be best if you could extend the root application.cfc and just override the onRequestStart method so that the framework will ignore the request. To do that you would need to make a mapping in the cfadmin to the root of your project and use this for your remoting/application.cfc
<cfcomponent extends="mappingName.Application">
<cffunction name="onRequestStart">
<cfargument name="requestname" required="true" />
<cfset structDelete(this,'onRequest')>
<cfset structDelete(this,'onRequestEnd')>
<cfset structDelete(VARIABLES,'onRequest')>
<cfset structDelete(VARIABLES,'onRequestEnd')>
<cfreturn true>
</cffunction>
</cfcomponent>
The way that wheels uses `cfinclude' all over the place, you may need to look at this post about extending the appliciation: http://techblog.troyweb.com/index.php/2011/09/cfwheels-workarounds-numero-uno-application-proxy/
There are some wheels plugins (http://cfwheels.org/docs/1-1/chapter/wheels-ajax-and-you) that allow you to use the controller actions / views / routes via ajax so you could look into those also.

How can I tell if a user belongs to an role in active directory - using ColdFusion

If I am using integration authentication in IIS, how can I determine if the current user is part of a specific active directory role, using ColdFusion.
This would be analogous to using the IsInRole() method of the User object in .net - how can it be done in ColdFusion
the only way to do this is to use cflap and query the active directory server to get a list of groups. after you've gotten the list, you will need to parse it to see if that user belongs to the group in question. below is some code i wrote with some comments for the people at work. values have been changed to protect the innocent.
<!--- getting the user login id --->
<cfset variables.thisuser = ListLast(cgi.AUTH_USER, "\")>
<!--- this is the group they must be a memberof --->
<cfset variables.groupname = "CN=<the group to search for>">
<!--- list of all groups that the user belongs to, will be populated later --->
<cfset variables.grouplist = "">
<cftry>
<cfldap action="query"
name="myldap"
attributes="memberOf"
start="OU=<your ou>,DC=<your dc>,DC=<your dc>"
scope="subtree"
filter="(sAMAccountName=#variables.thisuser#)"
server="<your AD server ip>"
port="<your AD server port>"
username="<network login if required>"
password="<network password if required>">
<cfset variables.grouplist = myldap.memberOf>
<cfcatch>
</cfcatch>
</cftry>
<cfif FindNoCase(variables.groupname, variables.grouplist)>
<cfcookie name="SecurityCookieName" value="">
</cfif>
In coldfusion to check a users role you would use IsUserInRole()
http://cfquickdocs.com/#IsUserInRole
Edit - And actually I hope I understood correctly, I don't know anything about IIS or active directory. As I understood the question you wanted to check a users role in Coldfusion.
I think you may be looking for something more like this: http://vincentcollins.wordpress.com/2008/08/20/active-directory-ldap-authentication/ or this: http://coldfusion.sys-con.com/node/154225
Just as a follow up, SQL server has ADSI providers that allow you to create a linked server to your LDAP servers.
From there you can do ldap queries to your AD and it returns like any other record set.
I find it a little easier to do complex ldap query then via CF.

Is onApplicationStart is good Idea in ColdFusion?

I have to use a Variable(Query Resultset) in ColdFusion, which will get the results from Other Application DB, and stores in Coldfusion Application.
The main idea is that I need to call the other Application DB only at Server startup time and cache the results in local. And I need to read the variable in other pages in my Application. I won't overwrite that variable in any page.
On googling I found that 'onApplicationStart' is useful to assign the variables at Application Startup time.
Is using the onApplicationStart fine or is there any other way? We can assign a variable at startup time(one time).
If onApplicationStart is fine: how to use? Maybe any link where it is explained clearly is helpful.
Well, it depends. How often will this query data be updated? If it really is unchanging, then onApplicationStart() is a fine place to put it. However, if it will change every so often, you can just tell Coldfusion to cache the query for a certain period of time, then you don't need to mess with onApplicationStart(), but rather when you call the query it will return the cached result automatically (within your specified time period).
Regardless, I would write a custom function to retrieve the data. Then it will be trivial to call it from onApplicationStart() or elsewhere.
Startup.cfc: (Named whatever you like)
<!--- Replace the datasource name with your db name --->
<cffunction name="getStartupQuery" hint="Returns a query recordset for startup">
<cfargument name="datasource" required="no" type="string" default="OtherAppDB">
<!--- Init the query variable --->
<cfset var result = queryNew("id")>
<!-- Get the query dataset --->
<cfquery name="result" datasource="#arguments.datasource#">
YOUR QUERY HERE
</cfquery>
<cfreturn result>
</cffunction>
Application.cfc: (Just the important parts)
<cffunction name="onApplicationStart">
<!--- init the startup.cfc, then retrieve the data
and save it to the application scope. Remember the component name must match
your component above --->
<cfset var startup = createObject("component", "startup")>
<cfset application.varFromOtherDB = startup.getStartupQuery()>
<cfreturn true>
</cffunction>
Now, you should be able to access this variable from any CFM or CFC in your application using:
<cfset myNewVar = application.varFromOtherDB>
or
#application.varFromOtherDB#
IF you use the onApplicationStart() method, I highly recommend implementing a method to reinit the application. For an example, see this other discussion.