ColdFusion crashes frequently after upgrading from CF 8 to CF2018 - coldfusion

We are facing some issues with the server crashing frequently after upgrading from ColdFusion 8 to ColdFusion 2018.
We have tried the performance tuning tool and fixed all the issues found. Still its crashing at least 1 to 2 times daily.
We have fixed some issues, like font missing errors by updating fonts, and fixed the issues found in the `coldfusion-out.log1.
Now we are checking the iterations, SQL queries if there's any chance of a sql timeout or something like that.
Apart from this, is there anything specifically we have to do to solve issues like server shutdown?

My suggestion. Install FusionReactor monitoring tool ASAP. That will tell you if you have queued up requests or if there is something else going on.
It is one of the best tools I have ever used.

There are two possibilities for this:
1) You have updated Coldfusion but have not updated your database version (specifically oracle). This can lead to CF using a outdated connector driver which can cause DB connections to occasionally hangup which in turn causes the CF server to become unresponsive. If this is the case, updating your DB can solve the issue.
2) Look at how you are storing client variables. If they are stored in registry, the server can crash intermittently. Better to change the storage to database OR none if you are not using any client variables. Keep in mind that client variables do not affect session activities like auto-logout etc.

It could be session related. Every time a client enters into a session Coldfusion seems to leave a footprint and may be holding onto a piece of memory, based on your cookie expiration. I am going to guess your server is incrementally eating up memory. One solution is to reduce the clients entering into sessions and the other is the age old CF solution (e.g. add gobs of ram to your server).
Here is some code you can add to quickly reduce the number of lengthy sessions, based upon the needs of your website. I've used this and it helps but won't eliminate memory hungry CF applications completely.
<cfif (
(NOT Len( cgi.http_user_agent )) OR
REFind( "bot\b", cgi.http_user_agent ) OR
Find( "crawl", cgi.http_user_agent ) OR
REFind( "\brss", cgi.http_user_agent ) OR
Find( "feed", cgi.http_user_agent ) OR
Find( "news", cgi.http_user_agent ) OR
Find( "blog", cgi.http_user_agent ) OR
Find( "reader", cgi.http_user_agent ) OR
Find( "syndication", cgi.http_user_agent ) OR
Find( "coldfusion", cgi.http_user_agent ) OR
Find( "slurp", cgi.http_user_agent ) OR
Find( "google", cgi.http_user_agent ) OR
Find( "zyborg", cgi.http_user_agent ) OR
Find( "emonitor", cgi.http_user_agent ) OR
Find( "jeeves", cgi.http_user_agent )
)>
<cfset THIS.name = "myWebsite_06302019">
<cfset THIS.sessionManagement="Yes">
<cfset THIS.sessiontimeout="#createtimespan(0,0,0,5)#">
<!---<cfset THIS.sessioncookie.timeout = "7" >--->
<cfset THIS.sessioncookie.timeout = "-1" >
<cfelse>
<cfset THIS.name = "myWebsite_06302019">
<cfset THIS.sessionManagement="Yes">
<cfset THIS.sessiontimeout="#createtimespan(0,0,180,0)#">
<!---<cfset THIS.sessioncookie.timeout = "7" >--->
<cfset THIS.sessioncookie.timeout = "#createtimespan(0,0,180,0)#" >
</cfif>

Related

ColdFusion 2021 - How to handle SAML/SSO with multiple applications on same server

We have a server with about a dozen small applications each in their own subfolder of the server (//URL/app1, //URL/app2, etc).
I've got the basic SSO authentication round trip working. I set up my account with my IDP and have the response set to go to a common landing page (ACS URL). Since the landing page is currently shared with all the apps, it is in a separate folder distinct from the apps (//URL/sso/acsLandingPage.cfm)
I'm now working on my first app. I can detect the user is not logged in so I do a initSAMLAuthRequest(idp, sp, relayState: "CALLING_PAGE_URL") and that goes out, authenticates, then returns to the landing page.
But how do I redirect back to my target application and tell it the user is authenticated?
If I just do a <cflocation url="CALLING_PAGE_URL" /> the original app doesn't know about the SAML request.
Is there a function that I can call in the original app that will tell if the current browser/user has an open session?
Do I need to set up separate SP for each application so rather than one common landing page each app would have its own landing page so it can set session variables to pass back to the main application? (the IDP treats our apps as "one server", I can get separate keys if that is the best way to deal with this).
My current working idea for the ACS landing page is to parse the relayState URL to find out which application started the init request and then do something like this:
ACSLandingPage.cfm
<cfset response = processSAMLResponse(idp, sp) />
<cfif find(response.relaystate, 'app1')>
<cfapplication name="app1" sessionmanagement="true" />
<cfelseif find(response.relaystate, 'app2')>
<cfapplication name="app2" sessionmanagement="true" />
</cfif>
<cfset session.authenticated_username = response.nameid />
<cflocation url="#response.relaystate#" />
Not terribly ideal, but I think it might work.
I was hoping I was just overlooking something simple and really appreciate any help I can get.
Edit:
My above idea of using <cfapplication in the ACSLandingPage is not working because the <cfapplication keeps trying to assign it to a new session so that when I redirect back to the original app, it thinks it is in a different session so does not have access to the original session.authenticated-username.
Ok, here's how I ended up solving this problem. Probably not the "correct" solution, but it works for me.
The full code solution would be way too long and complicated and rely on too many local calls that would not make sense, so I'm trying to get this down to just some code snippets that will make sense to show how my solution works.
In each application, the Application.cfc looks a bit like this. Each app has a name set to the path of the Application.cfc. We do this because we often will run "training instances" of the codebase on the same server that point to an alternate DB schema so users can play around without corrupting production data.
component {
this.name = hash(getCurrentTemplatePath());
...
In the application's onRequestStart function it has something a bit like this:
cfparam(session.is_authenticated, false);
cfparam(session.auth_username, '');
cfparam(application._auth_struct, {}); // will be important later
// part 1
// there will be code in this block later in the description
// part 2
if (NOT session.is_authenticated OR session.auth_username EQ '') {
var returnURL = '#getPageContext().getRequest().getScheme()#://#cgi.server_name#/#cgi.http_url#'; // points back to this calling page
// start the call
InitSAMLAuthRequest({
'idp' : 'IDP_NAME',
'sp' : 'SP_NAME',
'relayState': returnURL
});
}
// log them in
if (session.is_authenticated AND session.auth_username NEQ '' AND NOT isUserLoggedIn()) {
... do cflogin stuff here ...
}
// throw problems if we are not logged in by this point
if (NOT isUserLoggedIn()) {
... if we don't have a logged in user by this point do error handling and redirect them somewhere safe ...
}
This initiates the SAML connection to our ID Provider. The provider does its stuff and returns the user to the file 'https://myserver/sso/ProcessSAMLResponse.cfm'.
processSAMLResponse uses the returnURL set in relayState to determine which application initiated the request so it can get a path to the app's Application.cfc.
<cfset response = ProcessSAMLResponse(idpname:"IDP_NAME", spname:"SP_NAME") />
<cfset returnURL = response.RELAYSTATE />
<cfif findNoCase("/app1", returnURL)>
<cfset appPath = "PHYSICAL_PATH_TO_APP1s_APPLICATION.CFC" />
<cfelseif findNoCase("/app2", returnURL)>
<cfset appPath = "PHYSICAL_PATH_TO_APP2s_APPLICATION.CFC" />
<cfelseif findNoCase("/app3", returnURL)>
<cfset appPath = "PHYSICAL_PATH_TO_APP3s_APPLICATION.CFC" />
...
</cfif>
<!--- initiate application --->
<cfapplication name="#hash(appPath)#" sessionmanagement="true"></cfapplication>
<!--- create a token (little more than a random string and a bit prettier than a UUID) --->
<cfset auth_token = hash(response.NAMEID & dateTimeFormat(now(), 'YYYYmmddHHnnssL'))/>
<cfset application._auth_struct[auth_token] = {
"nameid": lcase(response.NAMEID),
"expires": dateAdd('n', 5, now())
} />
<!--- append token (can also be done with a ?: if you are inclined) --->
<cfif NOT find("?", returnURL)>
<cfset returnURL &= "?auth_token=" & encodeForURL(auth_token) />
<cfelse>
<cfset returnURL &= "&auth_token=" & encodeForURL(auth_token) />
</cfif>
<!--- return to the calling page --->
<cflocation url="#returnURL#" addToken="No"/>
This throws it back to the application. So we go back into the application's onRequestStart to fill in that part 1 block from above:
cfparam(session.is_authenticated, false);
cfparam(session.auth_username, '');
// part 1
// look for an auth token
if (NOT session.is_authenticated AND session.auth_username EQ '' AND structKeyExists(URL, 'auth_token')) {
var auth_token = URL.auth_token;
// see if it exists in our auth struct (and has all fields)
if ( structKeyExists(application, "_auth_struct")
AND structKeyExists(application._auth_struct, auth_token)
AND isStruct(application._auth_struct[auth_token])
AND structKeyExists(application._auth_struct[auth_token], 'nameid')
AND structKeyExists(application._auth_struct[auth_token], 'expires')) {
// only load if not expired
if (application._auth_struct[auth_token].expires GT now()) {
session.is_authenticated = true;
session.auth_username = application._auth_struct[auth_token].nameid;
}
// remove token from struct to prevent replays
structDelete(application._auth_struct, auth_token);
} // token in auth struct?
// remove expired tokens
application._auth_struct = structFilter(application._auth_struct, function(key, value) {
return value.expires GT now();
});
} // auth_token?
// part 2
// .... from earlier
So that's how I solved the problem of multiple apps trying to use a single IDP/SP combination.
Important caveats:
This is all done on an intranet server, so my security is much more lax than it would be on a public facing server. (in particular, using an application variable to store the auth-tokens could be vulnerable to a massive DDOS type attack that would flood new sessions and fill available memory).
A subset of 1 - these apps get a few hundred users a day across all apps, if you have a site that gets thousands of hits a day, storing the tokens in application like I do may not be memory efficient enough for you.
My IDP is very constrained. It would be much nicer if I could just create distinct SP settings for each app and have the return calls go directly back to the calling app.
I skipped a few checks and error handling to keep the sample simple. You should do lots more tests on the values, especially to make sure the nameID is a valid user before the actual cflogin call.
Before calling initSAMLAuthRequest, you may want to add a session counter to prevent an infinite loop of authentication calls if something goes wrong (learned that the hard way).

trouble using CFHTTPSession.cfc (cfhttp) to login to site

I'm trying to login to http://britishairways.com/ using Ben Nadel's CFHTTPSession.cfc, but am having trouble getting it to work. I'm not sure what I'm missing or overlooking.
Here is my code:
<cfset objResponse = objHttpSession
.NewRequest( "https://www.britishairways.com/travel/home/execclub/_gf/en_us" )
.Get()/>
<cfset objResponse = objHttpSession
.NewRequest( "https://www.britishairways.com/travel/loginr/public/en_us" )
.AddFormField( "membershipNumber", "#username#" )
.AddFormField( "password", "#password#")
.AddFormField( "Directional_Login","/travel/home/execclub/_gf/en_us" )
.AddFormField( "eId", "109001")
.AddFormField( "URLMembershipType", "onbusiness")
.AddFormField( "rememberLogin", "false")
.Post()/>
<cfset objResponse = objHttpSession
.NewRequest( "https://www.britishairways.com/travel/home/execclub/_gf/en_us" ).Get()/>
Most airlines (and other travel related sites) have quite tight systems around monitoring for what they would refer to as "screen scraping", e.g. automated attempts against their systems, so you are probably running into that as a road block.
Also by doing what you are doing you are in breach of their web site terms of use (http://www.britishairways.com/en-gb/information/legal/website-terms-conditions), specifically:
use ‘screen scraping’, any automated algorithm, device, method, system, software or manual process to access, use, search, copy, monitor or extract Material (in whole or in part) from or through using this website unless We have given Our express written agreement;
You could therefore face legal action against you from BA for what you are doing. I would stop.
Sorry, I'm sure that is not what you want to hear.

Best way to dynamically set host server in ColdFusion 10

I use the following to dynamically detect the host server. The importance for making it dynamic is that currently there are too many hard coded redirect such as:
http:s//mysite.com/hr/index.cfm
within my app.
When I'm moving from production site to development site and then back to production site, I have to manually change/comment out this http/https one by one and it is not only time consuming but also dangerous.
Here is the code I found that can detect the host server. Then I do the following:
<CFSET inet = CreateObject("java", "java.net.InetAddress")>
<CFSET inet = inet.getLocalHost()>
<CFSET HostServer = "#inet.getHostName()#">
<CFSET ThisHostServer = "#LEFT(HostServer,6)#">
<CFSWITCH expression="#Trim(ThisHostServer)#"><!--- Prod or Dev server --->
<CFCASE value="myprodsite.com">
<CFSET UseThisURL = "http://myprodsite.com">
</CFCASE>
<CFCASE value="mydevsite.com">
<CFSET UseThisURL = "http://myDevsite.com">
</CFCASE>
</CFSWITCH>
Then on each page where links or redirection exist, I just need to use:
#UseThisURL#/hr/index.cfm
My question is:
Where is the best way to set #UseThisURL# in the application?
I'm using ColdFusion 10 and Application.cfc in Linux env.
Should I set it as an application or a session scope?
Since everything will be in an application or session scope, when users are idle on a certain page and the application/session scope is expired, when user click on a link will it generate an error? How to prevent users from seeing error caused by using this technique? Please advice, thank you!
Best practice that I used is creating config.cfc which can contain function like getServerSpecificVariables() to return structure. this structure will be saved in your application scope since you don't want to create USEThisURL for every session start. When you need to reset simply clear your application scope. instantiate below config component inside onApplicationStart event in Application.cfc
Example
Config.cfc:
component{
public struct function getServerSpeceficVariables(){
var config = {};
var inet = CreateObject("java", "java.net.InetAddress");
inet = inet.getLocalHost();
HostServer = inet.getHostName();
ThisHostServer = LEFT(HostServer,6);
switch(Trim(ThisHostServer)){
case 'myprodsite.com':{
config.useThisURL = '';
break;
}
case 'mydevsite.com':{
config.useThisURL = '';
break;
}
}
return config;
}
}

access JRUN jndi environment vaiables from coldfusion (java)

I want to put some instance specific configuration information in JNDI. I looked at the information here:
http://www.adobe.com/support/jrun/working_jrun/jrun4_jndi_and_j2ee_enc/jrun4_jndi_and_j2ee_enc03.html
I have added this node to the web.xml:
<env-entry>
<description>Administrator e-mail address</description>
<env-entry-name>adminemail</env-entry-name>
<env-entry-value>admin#mystore.com</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
In coldfusion I have tried several different approaches to querying the data:
<cfset ctx = createobject("java","javax.naming.InitialContext") >
<cfset val = ctx.lookup("java:comp/env") >
That lookup returns a jrun.naming.JRunNamingContext. If i preform a lookup on ctx for the specific binding I am adding I get an error.
<cfset val = ctx.lookup("java:comp/env/adminemail") >
No such binding: adminemail
Preforming a listBindings returns an empty jrun.naming.JRunNamingEnumeration.
<cfset val = ctx.listBindings("java:comp/env") >
I only want to put a string value (probably several) into the ENC (or any JNDI directory at this point).
Never used it, but I got curious so I decided to try ... with no success.
I found this though, hopefully it helps you.
http://www.adobe.com/livedocs/coldfusion/7/htmldocs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=ColdFusion_Documentation&file=00001570.htm

How do I create Search Engine Safe URLs in Fusebox 5.1 noxml?

How do I create Search Engine Safe URLs in Fusebox 5.1 noxml?
For instance, I want this:
http://www.site.com/index.cfm/app.welcome/
Instead of this:
http://www.site.com/index.cfm?fuseaction=app.welcome
Fusebox 5.1 is suppose to be able to do this. I've read this article, but it only applies to the xml version. I know so little, I am not sure where to start. How do I do it with the noxml version of fusebox?
Update:
It looks like I need to add this to my Application.cfc file. Still not working though...
FUSEBOX_PARAMETERS.myself = "index.cfm/fuseaction/";
FUSEBOX_PARAMETERS.queryStringStart = "/";
FUSEBOX_PARAMETERS.queryStringSeparator = "/";
FUSEBOX_PARAMETERS.queryStringEqual = "/";
Fusebox 5.1 allows you to use SES URLs by allowing you to change ? & to /. You still need to provide your own rewriter. However, if you are able to upgrade to 5.5 it supposedly handles rewriting, too.
Example Rewriter
http://www.fusebox.org/forums/messageview.cfm?catid=31&threadid=6117&STARTPAGE=2
<cfscript>
// SES converter
qrystring = ArrayNew(1);
if ( Find("/",cgi.path_info) eq 1 and Find("/#self#",cgi.path_info) eq 0 ) {
qrystring = cgi.path_info;
} else if ( Len(Replace(cgi.path_info,"#self#/","")) gt 0 ) {
qrystring = ListRest(Replace(cgi.path_info,"#self#/","#self#|"),"|");
} else if ( FindNoCase("#self#/",cgi.script_name) gt 0 ) {
qrystring = ListRest(Replace(cgi.script_name,"#self#/","#self#|"),"|");
}
arQrystring = ListToArray(cgi.path_info,'/');
for ( q = 1 ; q lte ArrayLen(arQrystring) ; q = q + 2 ) {
if ( q lte ArrayLen(arQrystring) - 1 and not ( arQrystring[ Q ] is myFusebox.getApplication().fuseactionVariable and arQrystring[ q+1] is self ) ) {
attributes['#arQrystring[ Q ]#'] = arQrystring[ q+1];
}
}
</cfscript>
If you choose to use Coldcourse...
http://coldcourse.riaforge.com
Below will help you get started. You can ignore server-side rewriting (ISAPI for IIS) if you want /index.cfm/circuit/action/ formatted URLs. But if you want /circuit/action/ or /blah/ you'll need to make it server side.
application.cfc
Put on onApplicationStart (or onRequestStart for testing) to put in memory.
<cfset application.coldcourse = createObject("component","components.util.coldcourse").init("/config/coldcourse.config.cfm")>
index.cfm
Place this before the framework loads
<cfset application.coldcourse.dispatch(cgi.path_info, cgi.script_name) />
coldcourse.config.cfm (example config)
<cfset setEnabled(true)>
<cfset setFrameworkEvent("action")>
<cfset setFrameworkSeparator(".")>
<cfset setFrameworkActionDefault("")>
<cfset setUniqueURLs(true)>
<cfset setBaseURL("http://www.mysite.com/index.cfm")>
<!--- CUSTOM COURSES GO HERE (they will be checked in order) --->
<!--- for http://www.mysite.com/about/ pages --->
<cfset addCourse("components")>
<cfset addCourse(pattern="about",controller="main",action="about")>
<cfset addCourse(pattern="contact",controller="main",action="contact")>
<cfset addCourse(pattern="help",controller="main",action="help")>
<!--- If nothing else matches, fall back to the standard courses (you probably shouldn't edit these) --->
<cfset addCourse(":controller/:action/:id")>
<cfset addCourse(":controller/:action")>
<cfset addCourse(":controller")>
Install ISAPI Rewrite
Make sure you are using the correct rewrite regex because version 2.0 is different from 3.0.
Example for 2.0 script:
# Coldcourse URL Rewrite for CF
IterationLimit 0
RewriteRule ^(/.+/.+/.*\?.+\..*)$ /index.cfm/$1
RewriteRule ^(/[^.]*)$ /index.cfm/$1
Disable Check if File Exists on web server
Do this for IIS if you're getting a 404 error in your web logs.
Open the IIS manager
Right click on a site and choose Properties
Click the Home Directory tab
Click the Configuration button
(lower right of dialog)
Click the .cfm extension and choose
'Edit'
The lower left checkbox: "Check that
File Exists"
riaforge is your friend:
http://coldcourse.riaforge.org/