ColdFusion - Enabling ORM stops onApplicationStart from running - orm

Can anyone explain this behaviour to me?
I have set up a bunch of application scoped settings in onApplicationStart, and some of them are referred to in onSessionStart. However, when I enable ORM, it seems that onApplicationStart isn't running at all and thus my onSessionStart method fails.
It took me a while to figure out this was the issue, generally I'll test by hitting onApplicationStart programatically during development. So it was only after a restart of the service that I found a symptom. Eventually I traced it back to ORM and it's as simple as:
THIS.ormenabled = true; // Error
THIS.ormenabled = false; // Everything peachy
I stripped down the Application.cfc and put some timestamps in the various methods so that I could see what was executing:
<cfscript>
THIS.Name = "TestyMcTestable"
THIS.datasource = 'Test';
THIS.ormenabled = true;
</cfscript>
<cfsetting
requesttimeout="20"
showdebugoutput="false"
enablecfoutputonly="false"
/>
<cfset request.pseudo = Now() />
<cfset sleep(1500)>
<cffunction name="OnApplicationStart" access="public" returntype="boolean" output="false">
<cfset request.application = Now() />
<cfset sleep(1500)>
<!--- Return out. --->
<cfreturn true />
</cffunction>
<cffunction name="OnSessionStart" access="public" returntype="void" output="false">
<cfset request.session = Now() />
<cfset sleep(1500)>
<!--- Return out. --->
<cfreturn />
</cffunction>
<cffunction name="OnRequestStart" access="public" returntype="boolean" output="false">
<cfargument name="TargetPage" type="string" required="true" />
<cfset request.requeststart = Now() />
<cfset sleep(1500)>
<!--- Return out. --->
<cfreturn true />
</cffunction>
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true" />
<cfset request.request = Now() />
<cfset sleep(1500)>
<!--- Include the requested page. --->
<cfinclude template="#ARGUMENTS.TargetPage#" />
<!--- Return out. --->
<cfreturn />
</cffunction>
My index.cfm just contains a dump of the request scope.
If I remove the orm setting, it all comes back as expected. However with the setting in there, the variable set on application start is missing entirely and it seems onApplicationStart hasn't been run at all.
I'm testing by changing the name of the application inbetween requests, but just to be certain I've restarted the service too.
Am I missing something? Is this documented behavior? I'm running this on Railo - I haven't tested extensively on ACF, but the initial problem occurred there too so I assume it's the same cause.
Can anyone shed any light on this?

OnApplicationStart is only run when the Application is first created in memory and is only run once for the life of the Application unless you explicitly call things like ApplicationStop(); or call the method again, etc. In addition, the variable in the Application scope you set is a request scope variable which only exists for the lifetime of one request. Same with onSessionStart, that request variable will only exist when the user session is created for the first time.
First Request: (ApplicationStart & SessionStart Fire)
struct: request
application {ts '2013-03-20 18:50:17'}
cfdumpinited false
pseudo {ts '2013-03-20 18:50:20'}
session {ts '2013-03-20 18:50:19'}
struct: session
cfid 5600
cftoken a8bf96c34c2cac7a-68400880-E1E6-ACDF-3B204DBBCD9A04A9
session {ts '2013-03-20 18:50:19'}
sessionid TESTYMCTESTABLE_5600_a8bf96c34c2cac7a-68400880-E1E6-ACDF-3B204DBBCD9A04A9
urltoken CFID=5600&CFTOKEN=a8bf96c34c2cac7a-68400880-E1E6-ACDF-3B204DBBCD9A04A9
Second Request: (Application/SessionStart Do Not Fire)
struct: request
cfdumpinited false
pseudo {ts '2013-03-20 18:50:59'}
struct: session
cfid 5600
cftoken a8bf96c34c2cac7a-68400880-E1E6-ACDF-3B204DBBCD9A04A9
session {ts '2013-03-20 18:50:19'}
sessionid TESTYMCTESTABLE_5600_a8bf96c34c2cac7a-68400880-E1E6-ACDF-3B204DBBCD9A04A9
urltoken CFID=5600&CFTOKEN=a8bf96c34c2cac7a-68400880-E1E6-ACDF-3B204DBBCD9A04A9
This was tested on CF9.
application.cfm
<cfcomponent>
<cfscript>
this.Name = "TestyMcTestable";
this.ormenabled = true;
this.datasource = 'cfartgallery';
this.sessionManagement = true;
</cfscript>
<cfset request.pseudo = Now() />
<cfset sleep(1500)>
<cffunction name="OnApplicationStart" access="public" returntype="boolean" output="false">
<cfset request.application = Now() />
<cfset session.application = Now() />
<cfset sleep(1500)>
<!--- Return out. --->
<cfreturn true />
</cffunction>
<cffunction name="OnSessionStart" access="public" returntype="void" output="false">
<cfset request.session = Now() />
<cfset session.session = Now() />
<cfset sleep(1500)>
<!--- Return out. --->
<cfreturn />
</cffunction>
<cffunction name="OnRequestStart">
</cffunction>
</cfcomponent>
Alternatively if you put your request variables in the OnRequestStart, they will be there every time. Hope this helps.

Turns out this was a problem with the cfclocation setting. In the original app, it was pointing to an incorrect location. When I stripped the Application.cfc down for testing, I removed this setting - not realising that default behaviour is to traverse the folders from root looking for persistent CFCs.
It seems then that the app ran into a problem during that process which bombed out of onApplicationStart, but continued running the other functions in Application.cfc.
One of the guys on the Railo group identified an issue with using pseudo constructors in non-persistent CFCs that are read by the Hibernate engine. I'm not certain if that contributed to this issue, but it seems likely.

Related

Using ColdFusion REST API, how do I return a response in onError handler?

I'm trying to set up a REST Web Services with ColdFusion 10, and if I have an onError handler in Application.cfc to handle incorrect parameter error.
My Download API Service:
<cfcomponent rest="true" restpath="downloadStuff">
<cffunction name="downloadStuff" access="remote" returntype="String" httpmethod="GET">
<!--- parameters --->
<cfargument name="id" required="true" type="string" restargsource="query"/>
<cfargument name="account" required="true" type="string" restargsource="query"/>
<!--- download stuff logic --->
...
<cfreturn response>
</cffunction>
</cfcomponent>
It is expecting 2 parameters and user get a 500 error if parameters are not there. I don't want user to see the 500 error, I want user to see a normal response message asking user to add the missing parameter.
This is my onError handler in application.cfc
<cffunction name="onError" returntype="String" output="true">
<cfargument name="exception" required="true">
<cfargument name="eventname" type="string" required="true">
<!--- error logging here --->
<cfset response = "Please add missing parameters">
<cfreturn response>
When user enter incorrect parameters to API, I am getting 500 error with "cannot convert the value "Please add missing parameters" to a boolean".
How can I pass back a response message in onError? Is there a better way to handle incorrect parameters error and return a message to user?

How to consume API in ColdFusion 10

Can you please help me? I am trying to consume response in my ColdFusion application. Just wanted to try with this fake API before proceeding to the actual one.
I have created a component with two functions inside it. My cfc looks like this:
photoUploadNew.cfc
<cfcomponent displayname="test" hint="testing.." output="yes">
<cfsetting enablecfoutputonly="true" showdebugoutput="true">
<cffunction name="start" access="public" output="no" returntype="any" description="initialize the component">
<cfset variables.testUrl = "https://jsonplaceholder.typicode.com/posts">
<cfreturn this>
</cffunction>
<cffunction access="public" output="false" name="testGetReq" displayname="TestGetReq" description="testing" returntype="any">
<cfset variables.testUrl = "https://jsonplaceholder.typicode.com/posts">
<cfhttp
result="httpResponsetest"
url="#variables.testUrl#"
timeout="30"
method="get"
>
<cfhttpparam
type="header"
name="Content-Type"
value="application/json"
/>
</cfhttp>
</cfhttp>
<cfreturn httpResponsetest>
</cffunction>
</cfcomponent>
In my cfm page. I am trying to instantiate this component and print whatever I am getting as a response but I am not able to print anything out there.
<cfset testObj = CreateObject("component","usedGear_admin.cfc.photoUploadNew").testGetReq()>
<cfoutput >
#testObj#
</cfoutput>
Any help would be greatly appreciated.
I think you are using cfhttp result wrong here. When we do a cfhttp call,
<cfhttp
method="get"
result="httpResponsetest"
url="https://jsonplaceholder.typicode.com/posts"
timeout="30"
>
</cfhttp>
They try the following, you will see httpResponsetest has multiple keys. The data provided by API will be present in httpResponsetest.fileContent. Also most of the time there is Mimetype,Responseheader,Statuscode etc.
<cfdump var="#httpResponsetest.fileContent#">
Here you can see the data is in JSON format. That means you'll need to deserialize them to be able to use it.
<cfdump var="#deserializeJSON(httpResponsetest.fileContent)#">
You can deserialize it and return from the function. Along with that you'll need to handle the case where API responds with am error.
Demo

Taffy API framework Patch verb not working in lucee

I've created a taffy API endpoint in patch verb
I would run the explore to throw the below error
Patch verb working stable in ACF but not working in lucee
MY lucee version -> Lucee 4.5.4.017 final
Any one let me know how to fix that issue
Mycode:
<cfcomponent extends="taffy.core.resource" taffy_uri="/artist/">
<cfset variables.dummyData = StructNew() />
<cfset variables.dummyData.whatever = true />
<cfset variables.dummyData.phone = encode.string(5558675309) />
<cfset variables.dummyData.phoneNumeric = 5558675309 />
<cffunction name="patch" access="public" output="false">
<cfreturn representationOf(variables.dummyData).withStatus(200) />
</cffunction>
</cfcomponent>

Why the unknown error?

This is my error message:
ColdFusion could not delete the file
C:\path\guid.png
for an unknown reason.
I've already checked to make sure my coldFusion user has permission to do so, as suggested here. That is not the problem, the user has all the permissions. Unfortunately, the code is breaking on production servers, and not my own local server (could be relevant). Production is on CF11 but I am on CF9.
Here is the code:
<cffunction name="svgToPDF" access="public" output="false" returntype="string">
<cfargument name="svg" required="true" type="string" />
<cfset var local = {} />
<cfset local.guid = CreateUUID() />
<cfset local.outPDF = ExpandPath(local.guid & '.pdf') />
<cfset local.svg = DeserializeJSON(exportToImage(svg=arguments.svg)) />
<cfif local.svg.error>
<!-- Conversion error -->
<cfset FileDelete(#local.svg.file#) />
<cfreturn '' />
</cfif>
<!--- rotate the png --->
<cfimage
action="read"
source="#local.svg.file#"
name="local.objImage" />
<cfimage
action="rotate"
source="#local.objImage#"
angle="90"
name="local.objImage" />
<cfimage
action="write"
source="#local.objImage#"
destination="#local.svg.file#"
overwrite="yes" />
<!--- Add the png to the pdf, write the pdf file, and delete the png --->
<cfscript>
img = CreateObject("java", "com.lowagie.text.Image");
png = img.getInstance(local.svg.file);
document = CreateObject("java", "com.lowagie.text.Document");
document.init(png);
fileIO = CreateObject("java", "java.io.FileOutputStream");
fileIO.init(local.outPDF);
writer = CreateObject("java", "com.lowagie.text.pdf.PdfWriter");
writer.getInstance(document, fileIO);
document.setMargins(0, 0, 0, 0);
document.open();
document.add(png);
document.close();
FileDelete(#local.svg.file#); <!--- This is the line where it breaks--->
</cfscript>
<cfreturn local.outPDF />
</cffunction>
How can I fix this function?
Thanks
If you production server is CF11 then this is a bug that has been mentioned here, in Bug# 4031026 - http://bugbase.adobe.com/index.cfm?event=bug&id=4031026
The bug has been verified by Adobe and fix will be due, most probably in their next hotfix.
JPEG seems to be the only format that works at the moment without locking issues.

Cannot authenticate against Windows domain using ColdFusion 10, IIS 7.5, LDAP

We have been struggling on an upgrade from Windows 2003 Server (ColdFusion 8) to Windows 2008 with ColdFusion 10. We finally have the settings correct to handle and process all of our ColdFusion code, with custom error handlers, and SSL functioning as expected.
However, when we started to have some users test different applications, we found out that no Domain Users can log in to the website, unless they are part of the Local Machine's Administrators group. We have another Windows 2008 Server running .NET and authenticating users correctly. I thoroughly compared the settings and they are the same.
This is how it is setup:
ColdFusion Services: all services (5) are running under the Local System, with the exception of the ColdFusion Application Server, which is running under a domain account.
IIS: We have 1 active website (Main Website) running on it's own Application Pool Integrated .NET 4.0, running as LocalSystem.
Authentication: Anonymous works, Anonymous account MUST be Application Pool Identity or else it won’t display anything. Basic Authentication is configured, and the default domain is configured.
Any and all help is appreciated as we have been working on this for months and thought the migration was ready to go. No one on my team is an expert at the installation of ColdFusion or IIS 7.5.
After much ado, I found the answer here: What are the proper permissions for ColdFusion 9 on IIS 7.5 with Windows Authentication
I needed to give the domain users (which is just a very large A/D group) read-only access to the config folder under the CF10 install location. From then on, it worked great!
If you're interested in a fairly robust solution as well, here's an example component (CFC) you could call, which also scrubs out possible injection characters. We've evolved this over the years for authentication so it is fairly battle tested.
<cfcomponent output="false">
<cffunction access="public" name="init" output="FALSE" returntype="any" hint="This is the pseudo constructor that allows us to play little object games." >
<cfset variables.ldapserver = application.yoursiteLDAP.server />
<cfset variables.ldapuser = application.yoursiteLDAP.user />
<cfset variables.ldappassword = application.yoursiteLDAP.password />
<cfset variables.ldaptimeout = application.yoursiteLDAP.timeout />
<cfset variables.ldapsecuremode = application.yoursiteLDAP.securemode />
<cfset variables.port = application.yoursiteLDAP.port />
<cfreturn This />
</cffunction>
<cffunction name="authenticate" access="public" output="false" returntype="struct" hint="">
<cfargument name="username" type="string">
<cfargument name="password" type="string">
<cfset var returnData = StructNew() />
<cfset var queryResult = QueryNew('') />
<cfset var userInfo = "" />
<cfset arguments.username = scrubStringforLDAPQuery(arguments.username) />
<cfset userInfo = retrieveUserInfo(arguments.username) />
<cfset returnData["authenticated"] = false />
<cfset returnData["detail"] = "" />
<cfset returnData["user_info"] = QueryNew("") />
<cftry>
<cfldap
action="query"
server="#variables.ldapserver#"
username="#userInfo.DN#"
password="#arguments.password#"
filter="(&(uid=#arguments.username#)(objectClass=account))"
name="queryResult"
attributes="cn,dn,uid,displayName,objectClass,uidNumber"
start="dc=yoursite,dc=subdomain,dc=domain,dc=com"
maxrows="1"
port="#variables.port#"
timeout="#variables.ldaptimeout#"
secure="#variables.ldapsecuremode#" />
<cfset returnData["authenticated"] = queryResult.RecordCount EQ 1 />
<cfset returnData["user_info"] = queryResult />
<cfcatch>
<cfif FindNoCase("Invalid Credentials",cfcatch.Message) LTE 0>
<cfrethrow />
</cfif>
<cfset returnData["detail"] = cfcatch.Message />
</cfcatch>
</cftry>
<cfreturn returnData />
</cffunction>
<cffunction name="retrieveUserInfo" access="public" output="false" returntype="query" hint="">
<cfargument name="username" type="string">
<cfset var queryResult = QueryNew('') />
<cfset arguments.username = scrubStringforLDAPQuery(arguments.username) />
<cfldap
action="query"
server="#variables.ldapserver#"
username="#variables.ldapuser#"
password="#variables.ldappassword#"
filter="(&(uid=#arguments.username#)(objectClass=account))"
name="queryResult"
attributes="cn,dn,uid,displayName,objectClass,uidNumber,shadowExpire,gecos,homeDirectory,loginShell"
start="dc=yoursite,dc=subdomain,dc=domain,dc=com"
maxrows="10"
port="#variables.port#"
timeout="#variables.ldaptimeout#"
secure="#variables.ldapsecuremode#" />
<cfif queryResult.RecordCount GT 1>
<cfthrow message="More than 1 user found in LDAP" detail="More than 1 user matched uid=#arguments.username#" />
</cfif>
<cfreturn queryResult />
</cffunction>
<cffunction name="retrieveGroupInfo" access="public" output="false" returntype="query" hint="">
<cfargument name="groupname" type="string">
<cfset var queryResult = QueryNew('') />
<cfset arguments.groupname = scrubStringforLDAPQuery(arguments.groupname) />
<cfldap
action="query"
server="#variables.ldapserver#"
username="#variables.ldapuser#"
password="#variables.ldappassword#"
filter="(&(cn=#arguments.groupname#)(objectClass=posixGroup))"
name="queryResult"
attributes="cn,dn,objectClass"
start="dc=yoursite,dc=subdomain,dc=domain,dc=com"
maxrows="10"
port="#variables.port#"
timeout="#variables.ldaptimeout#"
secure="#variables.ldapsecuremode#" />
<cfif queryResult.RecordCount GT 1>
<cfthrow message="More than 1 group found in LDAP" detail="More than 1 group matched uid=#arguments.groupname#" />
</cfif>
<cfreturn queryResult />
</cffunction>
<cffunction name="scrubStringforLDAPQuery" access="public" output="false" returntype="string" hint="Removes offensive characters from string for use in an LDAP query">
<cfargument name="stringToScrub" type="string">
<cfargument name="blockWildcard" type="boolean" default="false">
<cfset replaceCharacterList = ";=" />
<cfif arguments.blockWildcard>
<cfset replaceCharacterList &= "*" />
</cfif>
<cfset arguments.stringToScrub = REReplace(arguments.stringToScrub,"[#replaceCharacterList#]","","all") />
<cfreturn arguments.stringToScrub />
</cffunction>
</cfcomponent>