I have a silly question but I am a newbie. I am trying to make a cross-domain request (via ajax) using extjs4 library. As server side language I am using ColdFusion. The whole code that I have written so far is working on same domain. I need to separate static files (javascript, css, and html) placing them on Apache server and the dynamic content (cfm, CFC) placing them over Tomcat (openbd). So the front end scripts (on Apache->javascript mainly) making requests on Tomcat in order to fetch content. This definitely is cross-domain requests.
A code block that I am using in order to pull data (CFC) is:
<cfcomponent output="false">
<cfprocessingdirective pageencoding="utf-8">
<cfset setEncoding("URL", "utf-8")>
<cffunction name="getContent" access="remote" returnFormat="JSON" output="false" >
<cfargument name="start" default="0"/>
<cfargument name="limit" default="1000"/>
<cfargument name="id" default="0" required="false" type="numeric">
<cfargument name="model" default="" required="false" type="any">
<cfset var arrNomoi = ArrayNew(1)>
<cfset var stcReturn = "">
<!--- When going back to base state, ExtJS will make the function call with start set to 0. If this is the case
we set it to 1 --->
<cfset Arguments.start = Arguments.start + 1>
<cfif arguments.model EQ 'n_2664_1998'>
<cfquery name="getNomoi" datasource="ktimatologio">
SELECT CONCAT_WS('_',id,model) AS id, id AS 'id1', CONCAT_WS(' ',title,fek,date) AS 'title', description, body, model
FROM n_2664_1998
WHERE id = #arguments.id#
ORDER BY id ASC
</cfquery>
<cfelseif arguments.model EQ 'n_2308_1995'>
<cfquery name="getNomoi" datasource="ktimatologio">
SELECT CONCAT_WS('_',id,model) AS id, id AS 'id1', CONCAT_WS(' ',title,fek,date) AS 'title', description, body, model
FROM n_2308_1995
WHERE id = #arguments.id#
ORDER BY id ASC
</cfquery>
<cfelseif arguments.model EQ 'n_3889_2010'>
<cfquery name="getNomoi" datasource="ktimatologio">
SELECT CONCAT_WS('_',id,model) AS id, id AS 'id1', CONCAT_WS(' ',title,fek,date) AS 'title', description, body, model
FROM n_3889_2010
WHERE id = #arguments.id#
ORDER BY id ASC
</cfquery>
</cfif>
<cfset arrNomoi = convertQueryToExtJS(getNomoi,Arguments.start,Arguments.limit)>
<cfset stcReturn = {"data"=arrNomoi,dataset=#getNomoi.RecordCount#}>
<cfreturn stcReturn>
</cffunction>
<cffunction name="convertQueryToExtJS" access="public" hint="Convert Query to JSON usable by ExtJS Grid" returntype="array">
<cfargument name="qryData" type="query" required="true" hint="Query to convert">
<cfargument name="intStart" type="numeric" required="true" hint="Start of Result Set">
<cfargument name="intLimit" type="numeric" required="true" hint="How many records to return">
<!--- For the Array --->
<cfset var i = 1>
<cfset var end = ((Arguments.intStart) + arguments.intLimit)-1>
<cfset var arrNomoi = ArrayNew(1)>
<cfloop query="qryData" startrow="#Arguments.intStart#" endrow="#end#">
<cfset stcNomoi = StructNew()>
<cfset stcNomoi['id'] = #qryData.id#>
<cfset stcNomoi['id1'] = #qryData.id1#>
<cfset stcNomoi['title'] = #qryData.title#>
<!---<cfset stcNomoi['fek'] = #qryData.fek#>
<cfset stcNomoi['date'] = #qryData.date#>--->
<cfset stcNomoi['description'] = #qryData.description#>
<cfset stcNomoi['body'] = #qryData.body#>
<cfset stcNomoi['model'] = #qryData.model#>
<cfset arrNomoi[i] = stcNomoi>
<cfset i = i + 1>
</cfloop>
<cfreturn arrNomoi>
</cffunction>
</cfcomponent>
The question is: how do I wrap the above function into a variable (named “callback”) and post it on client?
I have seen a similar code block on PHP but I don’t understand. Below is the PHP code block:
<?php
$callback = $_REQUEST['callback'];
// Create the output object.
$output = array('id' => 1, 'url' => 'loianegroner.com');
//start output
if ($callback) {
header('Content-Type: text/javascript');
echo $callback . '([' . json_encode($output) . ']);';
} else {
header('Content-Type: application/x-json');
echo json_encode($output);
}
?>
With respect,
Tom
Greece
Take a look at these two files:
The index.cfm is the handler where you submit an AJAX request to and it will return a JSON result
http://websvn.openbd.org/websvn/filedetails.php?repname=OpenBD&path=%2Ftrunk%2Fwebapp%2Fmanual%2Fapi%2Findex.cfm
The index.cfm interacts with this CFC to fetch the information and return the result.
http://websvn.openbd.org/websvn/filedetails.php?repname=OpenBD&path=%2Ftrunk%2Fwebapp%2Fmanual%2Fapi%2Findex.cfc
When I was writing this API wrapper I had issues with returnFormat=JSON
Related
I have been developing single page application that runs on ColdFusion 2016. I already developed login page and now I would like to develop security for each Ajax call that is sent to .cfc page. There is many functions in this file and my main focus is to check if user Session exists and to check if Logged in User has Admin or User access. There is set of functions that should be accessed only with Admin access. The other functions are available for both User and Admin. Here is example of my Session scope that keeps all user info after successfully passed authentication:
<cfset var appStruct = structNew()>
<cfset structInsert(appStruct, "SysAdmin", SystemAdmin, true)>
<cfset structInsert(appStruct, "UserName", UserName, true)>
<cfset structInsert(appStruct, "AccountID", AccountID, true)>
<cfset structInsert(appStruct, "Email", Email, true)>
<cfset SESSION.AccountInfo = appStruct>
Code above is executed once user is logged in, then I have check on the top of my .cfc file:
<cfcomponent>
<cfif structKeyExists(SESSION, "AccountInfo")>
<cfset LoggedAccountID = SESSION.AccountInfo.AccountID>
<cfset isAdmin = SESSION.AccountInfo.SysAdmin EQ 1 ? true : false>
<cfelse>
<cfabort>
</cfif>
/* Here I have many functions that are used by Users and Administrators. */
</cfcomponent>
Then on top of this in each cffunction I always check if AccountInfo session exists and if Admin access is set to true for Administrator functions. Example of one of the functions that is only accessed by Administrators:
<cffunction name="findAccount" access="remote" output="false" returnformat="JSON">
<cfargument name="sessionID" type="string" required="yes" default="fakeSession">
<cfargument name="frmFindaccount_search" type="string" required="yes">
<cfset var fnResults = structNew()>
<cfset var runProcess = true>
<cfif !isAdmin OR !structKeyExists(SESSION, "sessionid") OR (SESSION.sessionid NEQ arguments.sessionID) OR !structKeyExists(VARIABLES, "LoggedAccountID")>
<cfset var fnResults.status = "400">
<cfset var fnResults.message = "Credentials Error!">
<cfreturn fnResults>
<cfabort>
</cfif>
</cffunction>
I'm wondering if all steps above are enough to protect unauthorized users to access any functions/data in my system? Also the other questions is about this block of the code:
<cfif !isAdmin OR !structKeyExists(SESSION, "sessionid") OR (SESSION.sessionid NEQ arguments.sessionID) OR !structKeyExists(VARIABLES, "LoggedAccountID")>
<cfset var fnResults.status = "400">
<cfset var fnResults.message = "Credentials Error!">
<cfreturn fnResults>
<cfabort>
</cfif>
I have this on the top of each cffunction in my .cfc(some functions do not have !isAdmin). I'm wondering if this can be only placed on the top of my .cfc instead of having this in each function? If anyone see any code that can be improved or have any advise please let me know. This is my first individual project and I'm trying to follow standards and prevent security threads.
I have system that I built and for this project I used Ajax with JQuery. On back end I use ColdFusion and session management to handle users session variables. There is two situations (actually three if we consider closing the browser) where users session will end. One situation is if they click Logout then I have function that will clear SESSION scope with all information in it but session is not ended. Also CFID and CFTOKEN are still the same. Here is example of Logout function:
<cffunction name="LogOut" access="remote" output="yes" returnformat="JSON" hint="Used in session timeout handling">
<cfset fnResults = structNew()>
<cfset dt = createODBCDateTime(now())>
<cfif structKeyExists(SESSION,"LoggedIn")>
<cfset temp = structClear(SESSION)>
<cfset fnResults.status = "200">
<cfelse>
<cfset fnResults.status = "400">
<cfset fnResults.message = "Error!">
</cfif>
<cfreturn fnResults>
</cffunction>
Second scenario is once user session timeout. Here is example of that fucntion:
<cffunction name="timeoutSession" access="remote" output="yes" verifyclient="no" securejson="false">
<cfset temp = structClear(SESSION)>
</cffunction>
Both of these functions will clear the session scope but not end the user session. I have used cfdump to check session scope once user logs out and CFID/CFTOKEN remains the same. I'm wondering how session cna be ended once they hit LogOut or timeoutSession function? Also should I rewrite the CFID and CFTOKEN every time user logs in the system? Here is example of my Application.cfc:
<cfcomponent output="false">
<cfset THIS.name = "MyApplication">
<cfset THIS.sessionManagement = true>
<cfset THIS.applicationTimeout = CreateTimeSpan(0, 8, 0, 0)>
<cfset THIS.sessionTimeout = CreateTimeSpan(0, 2, 0, 0)>
<cfset THIS.requestTimeOut = "60">
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false">
<cfset APPLICATION.appStarted = now()>
<cfset APPLICATION.title = "My Application">
<cfset APPLICATION.functions = CreateObject("component","udfs").init()>
<cfset APPLICATION.sessionMinutes = 30>
<cfreturn true>
</cffunction>
<!--- Runs when your session starts --->
<cffunction name="OnSessionStart" access="public" returntype="void" output="false">
<!--- Clear the session. --->
<cfset StructClear( SESSION ) />
<!--- Set loggedin flag to false. --->
<cfset SESSION.loggedin = false>
<cfreturn />
</cffunction>
<!--- Run before the request is processed. --->
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cfset REQUEST.appCode = 'SPA'>
<cfset REQUEST.appName = 'Single Page Application'>
<cfset var page = listLast(arguments.thePage,"/")>
<!---<cfset onApplicationStart()>--->
<cfif !listFindNoCase("Login.cfm,Authentication.cfc",page)>
<cfif !structKeyExists(SESSION, "loggedin") OR SESSION.loggedin EQ false>
<cflocation url="Login.cfm" addToken="false">
</cfif>
</cfif>
<cfreturn true>
</cffunction>
</cfcomponent>
I'm not sure if session can be ended in Application.cfc or I have to do that in my cffunctions. Same for CFID and CFTOKEN what is the best place to set new values if user logs in again? If aynone have experience with this please let me know. I'm trying to prevent user to use the same session and raise level of security in my SPA.
Assume the following site architecture:
/Application.cfc
/index.cfm
/sub/Application.cfc
/sub/index.cfm
/login/index.cfm
Now, here's some really basic pseudo-code:
/Application.cfc:
<cffunction name="onSessionStart" returntype="Void" output="false">
<cfscript>
SESSION.IsLoggedIn = false;
return;
</cfscript>
</cffunction>
<cffunction name="onRequestStart" returnType="Boolean" output="false">
<cfargument name="targetPage" type="string" required="true">
<cfscript>
if (SESSION.IsLoggedIn)
REQUEST.Cart = {};
</cfscript>
<cfreturn true />
</cffunction>
/sub/Application.cfc
<cffunction name="onRequestStart" returnType="Boolean" output="false">
<cfargument name="targetPage" type="string" required="true">
<cfscript>
SUPER.onRequestStart(ARGUMENTS.targetpage);
</cfscript>
<cfif NOT SESSION.IsLoggedIn>
<cflocation url="/login/" addtoken="false" />
</cfif>
<cfreturn true />
</cffunction>
When I request /sub/index.cfm, I get the following exception: Element ISLOGGEDIN is undefined in a Java object of type class [Ljava.lang.String;.
On my local development machine, I have Debugging Information turned on, so I can see that the SESSION is initialized, at least from a cookie standpoint, but, as you can see, my SESSION variables is NOT initialized:
Session Variables:
cfid=149415
cftoken=b7740eb6d2219f83-619FF01B-78AC-C0A4-1997EC503DA43982
sessionid=PRUDENTIAL_2UA1130DBK_2_149415_b7740eb6d2219f83-619FF01B-78AC-C0A4-1997EC503DA43982
urltoken=CFID=149415&CFTOKEN=b7740eb6d2219f83-619FF01B-78AC-C0A4-1997EC503DA43982
I cannot understand why onRequestStart() is being called before onSessionStart(). Shouldn't onSessionStart() be called first?
Please consider two files (I am working inside Sessions). Inside my .cfm page, I am creating an instance of a component and setting some values like following:
reports.cfm
<cfset LineChartObj = createObject("component", "#LocalSessionDotPath#.lib.report.testchart").init() />
<cfset LineChartObj.setTitle("Type of Events") />
<cfset LineChartObj.setYAxisTitle("Event Rate") />
testchart.cfc (relevant functions)
<cffunction name="setTitle" returntype="void" output="false" access="public" hint="Set title for chart">
<cfargument name="_Title" type="string" />
<cfset variables.title = arguments._Title >
</cffunction
<cffunction name="setXAxisTitle" returntype="void" output="false" access="public" hint="Set xAxisTitle for chart">
<cfargument name="_xAxisTitle" type="string" />
<cfset variables.xAxisTitle = arguments._xAxisTitle >
</cffunction>
<cffunction name="getXAxisTitle" returntype="string" access="public" hint="Get xAxisTitle of chart">
<cfreturn variables.xAxisTitle>
</cffunction>
My questions are:
The function name defined as "_Title" in setTitle() function can be anything, right? Not mandatory to take "_Title" ?
In <cfset variables.title = arguments._Title >, from where does the variables.title came from. Does it has something to do with session scope?
Right. Whatever the name you use for the argument defines the name you need to use to refer to it in your function body.
The variables scope is the default 'private' scope of storing variables & functions in a CFC. The code just explicitly declare to store title in the variables scope.
http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7ff1.html
I have tried multiple tutorials on this topic from Forta.com and yet run into the same error:
"Error invoking CFC/....(file path)../wgn.cfc: Internal Server Error [Enable
debugging by adding 'cfdebug to your URL parameters to see more info]"
I am working on my local machine and testing as localhost. Running WinXP Pro with sp3. Using Coldfusion's web server.
Both my .cfm and .cfc are in the same folder under the the webroot. In my case:
c:\ColdFusion9\wwwroot\bridges(.cfm and .cfc here)
So, they are in a "bridges" folder under wwwroot.
The code should generate some autosuggest functionality when the user types in the input box. Instead, it just spits back the above error.
This is my cfc named wgn.cfc:
<cfcomponent output="false">
<cfset THIS.dsn="bridges">
<!--- Lookup used for auto suggest --->
<cffunction name="getWGN" access="remote" returntype="array">
<cfargument name="search" type="any" required="false" default="">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(1)>
<!--- Do search --->
<cfquery datasource="#THIS.dsn#" name="data">
SELECT tblIDs.ID
FROM tblIDs
WHERE (tblIDs.IDType = 'xxx') AND (tblIDs.ID Like ('#ARGUMENTS.search#%'));
</cfquery>
<!--- Build result array --->
<cfloop query="data">
<cfset ArrayAppend(result, searchIDs)>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
And this is the relevant part of the form from my .cfm page:
<cfform .....>
<cfinput name="searchIDs" type="text" autosuggest="cfc:wgn.getWGN({cfautosuggestvalue})">
//......more to form, obviously
</cfform>
UPDATE
Solution:
change
<cfset ArrayAppend(result, searchIDs)>
to
<cfset ArrayAppend(result, ID)>