I am testing consuming a web-service and I'm getting an error.
Here is the web-service component:
<cfcomponent >
<cffunction name="listBooks" access="remote" returntype="string" output="no" >
<cfquery name="getBooks" datasource="cfbookclub" >
SELECT bookID, title, bookDescription, genre
FROM books
ORDER BY title desc
</cfquery>
<cfsavecontent variable="bookList" >
<books>
<cfoutput query="getBooks" >
<book id="#getBooks.bookID#" >
<title>#XMLFormat( getBooks.title )#</title>
<description>#XMLFormat( getBooks.bookDescription )#</description>
<genre>#XMLFormat( getBooks.genre )#</genre>
</book>
</cfoutput>
</books>
</cfsavecontent>
<cfreturn bookList >
</cffunction>
Here is the consuming page:
<cfinvoke
webservice="http://127.0.0.1/books.cfc?wsdl"
method="listBooks"
returnvariable="rawXMLBookList" >
</cfinvoke>
Seems simple enough - I was actually trying to pass an argument "genre" when I got the initial error,
Web service parameter name category cannot be found in the provided parameters {genre}.
So I removed all reference to arguments, and STILL get this error
Web service operation with parameters {} cannot be found.
The error makes it sound like the web-service cannot be found, however if I cut and paste the url into my browser I get the expected XML doc...
There was another post like this on this site, but the problem was a base64 issue, I'm just returning txt so I don't think it's a similar problem, even through the error msg is similar.
Try adding the refreshWSDL argument to your <cfinvoke> call and see if that helps.
<cfinvoke
webservice="http://127.0.0.1/books.cfc?wsdl"
method="listBooks"
refreshwsdl="yes"
returnvariable="rawXMLBookList">
</cfinvoke>
Setting refreshwsdl="yes" reloads the WSDL file and regenerates the artifacts used to consume the web service.
Note you do not want to keep this setting for all of your requests. You just need to set it for one request to refresh the artifacts. Then you should change it back to refreshwsdl="no". Until you need it again.
Here is an excerpt from Charlie Arehart's Blog about the refreshWSDL argument:
Why should you have to refresh the web service metadata?
Just to back up for a moment, the problem stems from CF's attempt to help. On the first request for a given web service, CF does some caching to make future requests go faster, not caching the results of the web service method but rather the artifacts used by CF based on the description of the web service itself.
CF uses the web service description (WSDL) reported at the time of that first call to create a java proxy/stub based on that, which it then reuses on future calls from CF to that web service.
The issue arises if/when the web service metadata changes. CF won't know, and will continue to use the older cached proxy/stub, and your long-running code may fail if it doesn't match the new WSDL returned by the web service.
So we need a way to tell CF to refresh its cache of that proxy stub.
This new feature is certainly the easiest way to make that happen, but it's not the only way.
Related
Can I use ColdFusion tags in JavaScript? For example:
<script language="javascript" type="text/javascript">
function validateUser() {
var userName = document.getElementById("username");
<CFQUERY DATASOURCE="mydatasourcename" NAME="getUser">
select USER_ID,COUNT(*) from user u
where u.firstname=userName;
</CFQUERY>
<cfif getUser.recordCount EQ 0>
<!--- Show eroor message --->
<cfelse>
<!--- Assign userId to hidden field --->
document.getElementById("userid").value=#USER_ID#
</cfif>
}
</script>
<input type='textbox' name='username' id='username' onblur=validateUser()/>
<input type='hidden' name='userid' id='userid'/>
When the end user enters their username, I would like to check in a database if this username exists or not. If it exists, I have to keep the userid in the hiddenfield or else throw an error.
Am I doing this correctly? If it is wrong, could you suggest the correct way?
Long version: http://blog.adamcameron.me/2012/10/the-coldfusion-requestresponse-process.html
Short version: no, you're not doing it right.
Mid-sized StackOverflow-friendly version: CFML code runs on the server side of a request; JavaScript runs on the client browser. And to be clear: the ColdFusion server never communicates with the browser directly at all: there's a web server in between. The client browser requests a file, the web server is configured to pass .cfm requests to the ColdFusion server, and it runs its code, returning the resulting string (eg: an HTML web page) to the web server which then returns that to the browser. That HTML might include JavaScript (inline or as external requests) which the browser will then execute.
Hopefully from that you can see that there's no direct interaction between server-side code and client-side code.
You have two facilities at your disposal to get the two communicating asynchronously though. Firstly: CFML code writes out text, but that text can be JS which the browser then runs when it finally receives it. Something like:
<cfset msg ="G'day world">
<script>alert("<cfoutput>#msg#</cfoutput>");</script>
Once the CFML server has processed that, what gets sent back to the browser is:
<script>alert("G'day world");</script>
In this way server-side code data can be used in client-side process if the server-side code "writes out" the data as part of its response. The example above is very trivial and not a "good practice" way of going about this, but it demonstrates the technique.
If you need to use JS code on the client to communicate back with the server, your only (real) recourse is to make an AJAX request back to the server to pass it client-side information for further server-side processing and for the server to respond with something. It is outwith the scope of your question to explain how best to do this, but there is a tonne of information out there to do this.
CFML provides some "wizards" to write HTML and JS out for you to facilitate this, but on the whole this is a bad approach to achieving this end, so I will not recommend it. However I will point you to a project which offers HTML/JS/CSS solutions to the inbuilt CFML wizardry: https://github.com/cfjedimaster/ColdFusion-UI-the-Right-Way
Back to the short answer: no, you cannot do what you are setting out to do for very good reasons, but if you revise your approach, you can achieve the ends that you want.
What you need to look at is passing the form fields back to the server via AJAX (jQuery makes this very easy), and run your <cfquery> code in a separate request.
If you read that blog article I mention from the outset (discloure: I wrote it, but I wrote it specifically for situations like this), then you'll understand why.
If you get stuck when working on part of your solution: raise another question more focused on whatever part you are stuck on.
This shouldn't be too hard to answer, but the discussions and documentation I've found can be rather unclear.
First of all, a little bit of information about my setup:
I'm on a hosted environment, and going through our ColdFusion admin group can be time-consuming. Therefore, I'm using the
restInitApplication function to register my RESTful web service.
My webroot folder (where my Application.cfm is located) is in
"E:\docs\wwwroot". I can only see, add, edit folders/files from
wwwroot down. I have no idea what's in "e:\docs". I believe that up
above where I cannot see there is another Application.cfm that sets
such things as the serverType (development, staging, or production),
that we (and other ColdFusion sites hosted on this server) use in
various places in our application code.
My pdfRestfulAPI.cfc (the component containing my webservice function) is in this folder,
"e:\docs\wwwroot\RESTservices". My component code looks like this:
<cfcomponent rest="true" >
<cffunction name="pdfconvert" access="remote" returntype="binary"
output="false" produces="application/xml" method="get" >
<cfargument name="sourceWebPageURL" type="string" >
<cfset pdfDoc = "" >
<cfdocument name="pdfDoc"
format="PDF"
src="#sourceWebPageURL#"
saveAsName="sample.pdf" >
</cfdocument>
<cfreturn #pdfDoc#>
</cffunction>
</cfcomponent>
The function itself is not an issue. It just converts a web page to pdf--pass a URL, get a PDF version of that web page. When I set it up as non-RESTful API (SOAP/xml) it works just fine.
In my Application.cfm, I am attempting to register my web service using the following code:
<cfset restInitApplication( getDirectoryFromPath(getCurrentTemplatePath())
& "RESTservices" ) >
This gives me a dir_path attribute of "E:\docs\wwwroot\RESTservices", which seems correct to me. I've omitted the optional mapping_name attribute. When the documentation says that this "can be anything", that is not helpful.
The error that I get in my Application.cfm reads:
coldfusion.rest.RestAppAdapter$InvalidApplicationException: No mapping
found for path E:\docs\wwwroot\RESTservices
Hopefully, I've laid out the details in such a way that anyone could try this out and let me know what I'm doing wrong.
Thanks, everyone!
In Using WebSocket in point-to-point communication in Adobe ColdFusion 10 Dev Guide, the javascript object mysocket created by <cfwebsocket> can call an invoke() method that can literally invoke Any public method on Any CFC from JavaScript.
How is this Not a security risk? How shall a cfc / function protect against being invoked by websocket?
1. Create a CFM page index.cfm.
<script type="text/javascript">
function msgHandler(msgobj){
var txt = document.getElementById("myDiv");
var message = ColdFusion.JSON.encode(msgobj);
txt.innerHTML += message + "<br >" + "<br>";
}
function invokecfcfn(){
var fname= document.getElementById("fnname").value;
if (fname == "f2") {
alert("f2 selected");
mysocket.invoke("mycfc", "f2", ["echo"]);
}
else
mysocket.invoke("mycfc", fname);
}
</script>
<cfwebsocket name="mysocket" onmessage="msgHandler"/>
<form>
<select id="fnname">
<option>f1</option>
<option>f2</option>
<option>f3</option>
</select>
<input id="invokefn" name="invokefn" value="Invoke CFC function " type="button" onclick="invokecfcfn();">
<div id="myDiv">
</div>
</form>
2. Create a CFC mycfc.cfc that contains the function called from the client page.
<cfcomponent>
<cffunction name="f1" >
<cfreturn "Message returned from f1">
</cffunction>
<cffunction name="f2" returntype="string" >
<cfargument name="arg1" type="string" required="true" >
<cfset msg= "Message from wsssendmessage of f2 which you called with arg " & arg1>
<cfset wssendMessage(msg)>
<cfreturn "Message returned from f2">
</cffunction>
<cffunction name="f3" >
<cfthread action="run" name="t1" >
<cfloop index="i" from="1" to="10">
<cfset sleep(20000)>
<cfset wssendMessage("Message #i# from wsssendmessage of f3 #now()#")>
</cfloop>
</cfthread>
<cfreturn "Thread initiated in f3">
</cffunction>
</cfcomponent>
EDIT: not Any function, private function returns:
{
"clientid":39550088,
"ns":"coldfusion.websocket.channels",
"reqType":"invoke",
"code":4001,
"type":"response",
"msg":"The method f1 was not found in component mycfc.cfc."
}
UPDATE:
I tried moving mycfc.cfc to /com (outside of webroot) and added a mapping to /com and the functions can STILL be successfully invoked.
UPDATE: July 3, 2013
The Adobe Product Security Incident Response Team (PSIRT) is aware of
this issue and is actively engaged with the ColdFusion Product Team to
release a fix.
http://blogs.coldfusion.com/post.cfm/coldfusion-10-websocket-vulnerebility
UPDATE: July 9, 2013
Adobe has released a security hotfix for ColdFusion 10 for Windows,
Macintosh and Linux. This hotfix addresses a vulnerability
(CVE-2013-3350) that could permit an attacker to invoke public methods
on ColdFusion Components (CFC) using WebSockets.
http://www.adobe.com/support/security/bulletins/apsb13-19.html
I don't think you can fix this with ColdFusion as it currently stands (update: this was written prior to ColdFusion 10.0.11 being released; the issue has now been resolved by 10.0.11). I don't think Bruce's CFML-based answer - whilst it or a variation thereof would work - is really feasible in the real world.
I would probably fall back to using firewall rules: web socket requests come in on a specific port, so you could have a set of rules around requests on that port, and which methods are allowable over it.
This is not a great solution, but it's probably the most expedient given the situation.
I pointed to my research on the CF side of things in a comment to your original question, but it's probably better being linked to from here: "Web socket security issue: risk assessment & findings"
Coldfusion 10 websockets invoke feature does seem broken to me after actual testing and further investigation of the new documentation pages and other projects (this thing is complicated!). I spent over an hour trying to get something to execute before the invoked function is run. I can't!
There are new "channel listener functions" documented here:
http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSe61e35da8d318518767eb3aa135858633ee-7ff9.html
However, the documentation clearly states that the "invoke" feature doesn't have a listener function. It also appears Application.cfc or the cfc listener don't execute on each request at all when invoke is run.
This seems like a design flaw. The language needs more event listeners or you can't use websockets without adding security to every function in your application.
The security within each function could be done like the code below, but it is not very practical to modify every function in an application:
<cfscript>
local.meta=GetMetaData(this[url.method]);
if(not structkeyexists(local.meta, 'access') or local.meta.access NEQ 'remote'){
throw("Function access must be set to remote.");
}
</cfscript>
You could also consider using a web server proxy in front of Coldfusion and use regular expressions to verify the request information so that only the websocket portion of your application has to be open on the public websocket port. Nginx 1.4+ has support for websocket proxying now: http://nginx.org/en/docs/http/websocket.html
Note: I have not tested using nginx websocket proxy yet. If it works, this would be a far easier solution.
Adobe has released a security hotfix for ColdFusion 10 for Windows,
Macintosh and Linux. This hotfix addresses a vulnerability
(CVE-2013-3350) that could permit an attacker to invoke public methods
on ColdFusion Components (CFC) using WebSockets.
http://www.adobe.com/support/security/bulletins/apsb13-19.html
Invoking public method after Update 11 is applied will return "code":4001 & "msg":"The method f1 in component mycfc cannot be accessed remotely."
It is certainly not a security risk for Javascript, or any other client for that matter, to be able to invoke any public method on any CFC. That is the expected behaviour for interfaces that you choose to expose as public. To solve this, the ColdFusion Team has to return to their original design of Websocket and redo it.
We are making a cfhttp call to connect to an https web service.
We are getting the this error:
Connection Failure: Status code unavailable
I searched Google but have found no solutions.
From the production server I am able to hit the web service URL.
I am a .Net developer and I am not sure of this technology.
Any pointers will be helpful.
Here is the line of code we are using to make the connection:
<cfhttp url="#arguments.TheIP#" method="post" throwonerror="true" timeout="45">
<cfhttpparam type="header" name="SOAPACTION" value="#arguments.TheHeader#">
<cfhttpparam type="XML" value="#arguments.TheXML#">
</cfhttp>
I have faced / solved this a few times, the snippet below hopefully will work for you. I highly recommend learning about it in stead of simply trying it.
I place this in my Application.cfc, but you could put it right in your script right before the cfhttp call as well.
<!--- fix for HTTPS connection failures --->
<cfif NOT isDefined("Application.sslfix")>
<cfset objSecurity = createObject("java", "java.security.Security") />
<cfset objSecurity.removeProvider("JsafeJCE") />
<cfset Application.sslfix = true />
</cfif>enter code here
Hum... First thing that appears odd is your IP argument as mentioned by barnyr. The response you are getting makes me think you are getting NO response at all (the request is completely ignored, not just erring). So some setting is causing them to ignore your request.
As of CF9 I use cfscript to do this kind of thing via HTTP when I can't use regular webservice java object proxy stubs.
Here is a working SOAP call via http() (because of .net to cf inability to communicate complex object hash maps via regular soap I resorted to this, among other things).
This is a cf to .net service call so it might be relevant for you as they are using just the built in tools to gen their SOAP service which was not perfectly Axis 1 SOAP happy-go-lucky.
In particular I had to play with some of the extra settings and headers to get it just so and specifically add the soap action into a header (which is usually derived from the SOAP body envelope).
Additionally, I am using oasis security which I had to stuff inside the envelope/body.
Here is the code (inside a cfc) that you might try updated as you need:
//////////////////////////////////////////////////////////////////////////
// BUILD HTTP REQUEST
//////////////////////////////////////////////////////////////////////////
Local['SoapAction'] = "XYZ.Commercial.Mapping.ServiceContracts/IService/#Arguments.szMethodName#"; // THIS IS CASE SENSITIVE
var oH = new Http();
oH.setMethod('post');
oH.setCharset('utf-8');
oH.setUserAgent('Axis/1.2.1');
oH.setTimeout(30);
oH.setURL(Arguments.szURL);
// INCLUDING THE SOAPACTION AS A HEADER IS SPECIFIC TO XYZ - USUALLY THE OPERATION IS DECIPHERED FROM THE ENVELOPE BODY TAGS - XYS REQUIRES THIS PATHING TO MATCH FOR THE SOAP ACTION HEADER VALUE
oH.addParam(type="HEADER", name="SOAPAction", value='#Local.SoapAction#');
oH.addParam(type="HEADER", name="Content-Type", value='text/xml');
oH.addParam(type="body", value=Arguments.szBody);
///////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// EXECUTE HTTP
Local['rsHttpSend']= oH.send();
// SET RESULTS
Local.nStatusCode = val(Local.rsHttpSend.getPrefix().StatusCode);
Local.szResponse = Local.rsHttpSend.getPrefix().FileContent;
Local.szHeader = Local.rsHttpSend.getPrefix().Header;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
This approach was coupled with using SoapUI to verify the final soap body post was valid. So if you can do that too, you should be able to use this vector.
Let me know if you get any farther.
Here are a list of things to check:
The variable for the URL is TheIP. Make sure this actually a properly
formatted URL, not just a URL.
Check that the target server's certificate is installed in the JVM's
trust store. in Windows and I think .Net, the system's own
certificate store is used, so if your browser can get to the URL
you're ok. In Java there is a file which contains a list of Trusted
Certs. Instructions on importing those certs are in the CF docs for
CFHTTP.
Check the ColdFusion logs for evidence of failure.
c:\coldfusion9\logs\exception.log is probably a good place to start.
Make sure your cfhttp link is correct. I face this issue and it totally based on incorrect cfhttp link.
We have a dedicated server running CentOS and Coldfusion 8.
All cfmail email is routed through Google with cfmail and smtp.
Every now and then, when cfmail is used, the 'FROM' field uses an address from a totally different website.
For instance:
Use form on Site A
Get an email: "Subject: On Site A From: siteb#siteb.com"
Where the from is a completely different variable in another set of code on another part of the server- there is no reason it should see this.
On the other side, sometimes sending an email to sitea#sitea.com has email wind up in Site B inbox, a completely different Google account.
What causes this to happen? Some kind of memory/cache issue? Or is there a funky DNS record causing issue?
Example:
Application.cfm (starts with some UDF includes, and then):
<cfinvoke component="#request.componentPath#.variables" method="getGlobal" />
Variables.cfc (a lot of variables defined within, but here is the cfmail vars):
<cffunction name="getGlobal" access="public" output="false" returntype="void">
<cfscript>
request.siteEmail = "email#mysite.com";
request.siteMailServer = "smtp.gmail.com";
request.siteMailUsername = "root#mysite.com";
request.siteMailPassword = "[redacted]";
</cfscript>
</cffunction>
It sounds like it's possible it could be a var scoping issue, but we can't know for sure until you share some code...
Looks like you're running multiple sites? there's a setting in the CF caching page in admin to do with caching web server paths:
From http://help.adobe.com/en_US/ColdFusion/9.0/Admin/WSc3ff6d0ea77859461172e0811cbf3638e6-7ffc.html :
Disabling the cacheRealPath attribute To ensure that ColdFusion always returns pages from the correct server, disable Cache Web Server Paths in the Caching page of the ColdFusion Administrator. (When you use the multiserver configuration, set the cacheRealPath attribute to false for the ProxyService in the jrun_root/servers/servername/SERVER-INF/jrun.xml file.)
Might not be it, but it's at least quick to try out.