Coldfusion 8 respond to particular error - coldfusion

I am writing an API which exposes parts of our database to a client. Part of this API requires certain HTML response codes to be sent for particular conditions. This is generally easy with simple checks, but I can not see how to catch (for example) 'InvalidDateTimeException' errors where an invalid date is submitted to SQL.
I have tried dumping the ERROR and cfcatch variables, but while they generate huge stack traces I cannot see any field that is easily parsable to check the specific type of error (short of doing a text search on the error message or stack trace).
I could also do a pre-check with regex such as
(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})
but this could still generate invalid dates. Coldfusion also provides some date validation, but I have read that it is particularly bad. This also wouldn't help other scenarios that don't deal with dates.
So in brief: What is the best way to react to a particular error such as 'InvalidDateTimeException' in coldfusion?
[Edit]
Some clarifications from the comments - We are using MYSQL 5 and cfqueryparams. We use the 'euro' date format here in Australia but it would be much prefered if the api user presented ISO format dates (yyyy-mm-dd) to avoid confusion.

Well .... my advice to use is to catch the error before it gets to SQL. You didn't specify your DBMS (SQL Server, MySQL, etc), so I'll focus on ColdFusion solutions. I hope one of these suggestions point you in the right path.
Options:
The article that you linked to concerning Coldfusion date validation mentions the isValid function as the recommended solution. Consider using that with the USDATE validation type, as suggested.
If you are using CFCs or at least cffunctions for your API methods, then you have cfargument type="date" at your disposal to assist with ensuring the dates are valid (although my feeling is that would have the same lenient behavior as isDate)
Inside of your cfquery tag, you should be using cfqueryparam for all of the parameters you pass, especially those passed directly from the user (whether a form post or a API call). You should use cfqueryparam cfsqltype=CF_SQL_DATE
Using any of the methods above (or all of them) you should wrap your coldfusion code in a try/catch construct and have a much easier error to deal with.
Depending on your DBMS, you might have access to Try/catch constructs there too.
**** UPDATED:
After reading your comment about the international conversion issues, I have two approaches that I'd choose between:
Keep in mind that I haven't tested any code or anything ....
First, maybe the international functions can help you.
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_in-k_37.html
Use Setlocale to set the location to English (Australian) and then use LSParseDateTime to read in the yyyy-mm-dd format and then use dateformat to write it to mySQL using mm/dd/yyyy or whatever dateformat it expects. I don't have much experience dealing with those LS functions though.
Second option, use the regex you provided to make sure that the input has the right structure, then use createDate to create a date in US format using the parsed mm dd and yyyy elements. Validate the usdate using isValid.
Here's a blindly coded attempt at the second option. Remember, I haven't tested this code. I'm heavily using the list function listGetAt to split the inputted datetime into separate date and time strings and then using listGetAt to parse out the individual date parts.
<cfscript>
isosampledate = "2013-06-05 14:07:33";
passesValidation = false;
expectedDatePattern = "\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}";
try {
if (refind(expectedDatePattern,isosampledate)) {
datePortion = listGetAt(isosampledate,1," ");
timePortion = listGetAt(isosampledate,2," ");
yearPart = listGetAt(datePortion,1,"-");
monthPart = listGetAt(datePortion,2,"-");
dayPart = listGetAt(datePortion,3,"-");
hoursPart = listGetAt(timePortion,1,":");
minutesPart = listGetAt(timePortion,2,":");
secondsPart = listGetAt(timePortion,3,":");
thisUSDate = createDateTime(yearPart,monthPart,dayPart,hoursPart,minutesPart,secondsPart)
if (isValid("usdate",thisUSDate) {
passesValidation = true;
sqlDate = CreateODBCDateTime(thisUSDate);
}
}
} catch (e:any) {
passesValidation = false;
}
</cfscript>
I'm pretty sure that if the inputted value was not a valid date then at least one of those date functions would throw an exception which would get picked up by the catch block.
Hope this helps. I'm off to bed.

Related

With stored procedures, is cfSqlType necessary?

To protect against sql injection, I read in the introduction to ColdFusion that we are to use the cfqueryparam tag.
But when using stored procedures, I am passing my variables to corresponding variable declarations in SQL Server:
DROP PROC Usr.[Save]
GO
CREATE PROC Usr.[Save]
(#UsrID Int
,#UsrName varchar(max)
) AS
UPDATE Usr
SET UsrName = #UsrName
WHERE UsrID=#UsrID
exec Usr.[get] #UsrID
Q: Is there any value in including cfSqlType when I call a stored procedure?
Here's how I'm currently doing it in Lucee:
storedproc procedure='Usr.[Save]' {
procparam value=Val(form.UsrID);
procparam value=form.UsrName;
procresult name='Usr';
}
This question came up indirectly on another thread. That thread was about query parameters, but the same issues apply to procedures. To summarize, yes you should always type query and proc parameters. Paraphrasing the other answer:
Since cfsqltype is optional, its importance is often underestimated:
Validation:
ColdFusion uses the selected cfsqltype (date, number, etcetera) to validate the "value". This occurs before any sql is ever sent to
the database. So if the "value" is invalid, like "ABC" for type
cf_sql_integer, you do not waste a database call on sql that was never
going to work anyway. When you omit the cfsqltype, everything is
submitted as a string and you lose the extra validation.
Accuracy:
Using an incorrect type may cause CF to submit the wrong value to the database. Selecting the proper cfsqltype ensures you are
sending the correct value - and - sending it in a non-ambiguous format
the database will interpret the way you expect.
Again, technically you can omit the cfsqltype. However, that
means CF will send everything to the database as a string.
Consequently, the database will perform implicit conversion
(usually undesirable). With implicit conversion, the interpretation
of the strings is left entirely up to the database - and it might
not always come up with the answer you would expect.
Submitting dates as strings, rather than date objects, is a
prime example. How will your database interpret a date string like
"05/04/2014"? As April 5th or a May 4th? Well, it depends. Change the
database or the database settings and the result may be completely
different.
The only way to ensure consistent results is to specify the
appropriate cfsqltype. It should match the data type of the target
column/function (or at least an equivalent type).

Handling invalid dates in Oracle

I am writing simple SELECT queries which involve parsing out date from a string.
The dates are typed in by users manually in a web application and are recorded as string in database.
I am having CASE statement to handle various date formats and use correct format specifier accordingly in TO_DATE function.
However, sometimes, users enter something that's not a valid date(e.g. 13-31-2013) by mistake and then the entire query fails. Is there any way to handle such rougue records and replace them with some default date in query so that the entire query does not fail due to single invalid date record?
I have already tried regular expressions but they are not quite reliable when it comes to handling leap years and 30/31 days in months AFAIK.
I don't have privileges to store procedures or anything like that. Its just plain simple SELECT query executed from my application.
This is a client task..
The DB will give you an error for an invalid date (the DB does not have a "TO_DATE_AND_FIX_IF_NOT_CORRECT" function).
If you've got this error- it means you already tried to cast something to an invalid date.
I recommend doing the migration to date on your application server, and in the case of exception from your code - send a default date to the DB.
Also, that way you send to the DB an object of type DbDate and not a string.
That way you achieve two goals:
1. The dates will always be what you want them to be (from the client).
2. You close the door for SQL Injection attacks.
It sounds like in your case you should write the function I mentioned...
it should look something like that:
Create or replace function TO_DATE_SPECIAL(in_date in varchar2) return DATE is
ret_val date;
begin
ret_val := to_date(in_date,'MM-DD-YYYY');
return ret_val;
exception
when others then
return to_date('01-01-2000','MM-DD-YYYY');
end;
within the query - instead of using "to_date" use the new function.
that way instead of failing - it will give you back a default date.
-> There is not IsDate function .. so you'll have to create an object for it...
I hope you've got the idea and how to use it, if not - let me know.
I ended up using crazy regex that checks leap years, 30/31 days as well.
Here it is:
((^(0?[13578]|1[02])[\/.-]?(0?[1-9]|[12][0-9]|3[01])[\/.-]?(18|19|20){0,1}[0-9]{2}$)|(^(0?[469]|11)[\/.-]?(0?[1-9]|[12][0-9]|30)[\/.-]?(18|19|20){0,1}[0-9]{2}$)|(^([0]?2)[\/.-]?(0?[1-9]|1[0-9]|2[0-8])[\/.-]?(18|19|20){0,1}[0-9]{2}$)|(^([0]?2)[\/.-]?29[\/.-]?(((18|19|20){0,1}(04|08|[2468][048]|[13579][26]))|2000|00)$))
It is modified version of the answer by McKay here.
Not the most efficient but it works. I'll wait to see if I get a better alternative.

Group by date field in solrj

i want to group the output i am getting through date type. But i am storing the data in solr using datetime type. Date Format i am using is
Date format :: "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
For e.g. Date is stored in solr as "2013-03-01T20:56:45.000+00:00"
What i want as output is count of dates :: for .e.g.
Date1:: "2013-03-01T20:56:45.000+00:00"
Date2:: "2013-03-01T21:56:45.000+00:00"
Date3:: "2013-03-01T22:56:45.000+00:00"
Date3:: "2013-03-02T22:56:45.000+00:00"
Date4:: "2013-03-02T23:56:45.000+00:00"
So i want the output as two columns ::
Date Count
2013-03-01 3
2013-03-02 2
Here is the code i am using
String url = "http://192.168.0.4:8983/solr";
SolrServer server = new HttpSolrServer(url);
SolrQuery query = new SolrQuery();
query.setQuery("*:*");
query.addFilterQuery("sessionStartTime:[2013-03-01T00:00:00Z TO 2013-03-04T24:00:00Z]");
query.add("group", "true");
query.add("group.field","uniqueId"); // uniqueId is grouping the data
query.add("group.main","true");
query.setRows(9999);
QueryResponse rs=server.query(query);
Iterator<SolrDocument> iter = rs.getResults().iterator();
Help is appreciated.
I know that this is an older question but I am working on something related to this so I thought I would share my solution. Since you are using grouping, rs.getResults() will likely be null. After reading through the SolrJ API and doing some testing on my end, you will find that the results are indeed grouped as you want them to be. To access them, create a variable like such:
List<Group> groupedData = rs.getGroupResponse().getValues().get(0).getValues()
Note that Group is the class org.apache.solr.client.solrj.response.Group
Then, iterate through groupedData, usinig groupedData.get(i).getResult() to get a SolrDocumentList of results for each grouped value. In your example, (assuming the data is ordered as you said it would be), groupedData.get(0) would give you a SolrDocumentList of the three matches that have the date 2013-03-01.
I understand that this is quite the chain of method calls but it does end up getting the results to you. If anyone does know a faster way to get to the data, please feel free to let me know as I would like to know as well.
Refer to the API for GroupResponse for more information
Note that this answer is working on Solr 5.4.0
The output that you are trying to achieve, I believe is better suited to Faceting over grouping. Check out the documentation on Date Faceting more specifically and SolrJ fully supports faceting, see SolrJ - Advanced Usage. For an introduction to Faceting I would recommend reading Faceted Search with Solr

How I can encode/escape a varchar to be more secure without using cfqueryparam?

How I can encode/escape a varchar to be more secure without using cfqueryparam? I want to implement the same behaviour without using <cfqueryparam> to get around "Too many parameters were provided in this RPC request. The maximum is 2100" problem. See: http://www.bennadel.com/blog/1112-Incoming-Tabular-Data-Stream-Remote-Procedure-Call-Is-Incorrect.htm
Update:
I want the validation / security part, without generating a prepared-statement.
What's the strongest encode/escape I can do to a varchar inside <cfquery>?
Something similar to mysql_real_escape_string() maybe?
As others have said, that length-related error originates at a deeper level, not within the queryparam tag. And it offers some valuable protection and therefore exists for a reason.
You could always either insert those values into a temporary table and join against that one or use the list functions to split that huge list into several smaller lists which are then used separately.
SELECT name ,
..... ,
createDate
FROM somewhere
WHERE (someColumn IN (a,b,c,d,e)
OR someColumn IN (f,g,h,i,j)
OR someColumn IN (.........));
cfqueryparam performs multiple functions.
It verifies the datatype. If you say integer, it makes sure there is an integrer, and if not, it does nto allow it to pass
It separates the data of a SQL script from the executable code (this is where you get protection from SQL injection). Anything passed as a param cannot be executed.
It creates bind variables at the DB engine level to help improve performance.
That is how I understand cfqueryparam to work. Did you look into the option of making several small calls vs one large one?
It is a security issue. Stops SQL injections
Adobe recommends that you use the cfqueryparam tag within every cfquery tag, to help secure your databases from unauthorized users. For more information, see Security Bulletin ASB99-04, "Multiple SQL Statements in Dynamic Queries," at www.adobe.com/devnet/security/security_zone/asb99-04.html, and "Accessing and Retrieving Data" in the ColdFusion Developer's Guide.
The first thing I'd be asking myself is "how the heck did I end up with more than 2100 params in a single query?". Because that in itself should be a very very big red flag to you.
However if you're stuck with that (either due to it being outwith your control, or outwith your motivation levels to address ;-), then I'd consider:
the temporary table idea mentioned earlier
for values over a certain length just chop 'em in half and join 'em back together with a string concatenator, eg:
*
SELECT *
FROM tbl
WHERE col IN ('a', ';DROP DATABAS'+'E all_my_data', 'good', 'etc' [...])
That's a bit grim, but then again your entire query sounds grim, so that might not be such a concern.
param values that are over a certain length or have stop words in them or something. This is also quite a grim suggestion.
SERIOUSLY go back over your requirement and see if there's a way to not need 2100+ params. What is it you're actually needing to do that requires all this???
The problem does not reside with cfqueryparam, but with MsSQL itself :
Every SQL batch has to fit in the Batch Size Limit: 65,536 * Network Packet Size.
Maximum size for a SQL Server Query? IN clause? Is there a Better Approach
And
http://msdn.microsoft.com/en-us/library/ms143432.aspx
The few times that I have come across this problem I have been able to rewrite the query using subselects and/or table joins. I suggest trying to rewrite the query like this in order to avoid the parameter max.
If it is impossible to rewrite (e.g. all of the multiple parameters are coming from an external source) you will need to validate the data yourself. I have used the following regex in order to perform a safe validation:
<cfif ReFindNoCase("[^a-z0-9_\ \,\.]",arguments.InputText) IS NOT 0>
<cfthrow type="Application" message="Invalid characters detected">
</cfif>
The code will force an error if any special character other than a comma, underscore, or period is found in a text string. (You may want to handle the situation cleaner than just throwing an error.) I suggest you modify this as necessary based on the expected or allowed values in the fields you are validating. If you are validating a string of comma separated integers you may switch to use a more limiting regex like "[^0-9\ \,]" which will only allow numbers, commas, and spaces.
This answer will not escape the characters, it will not allow them in the first place. It should be used on any data that you will not use with <cfqueryparam>. Personally, I have only found a need for this when I use a dynamic sort field; not all databases will allow you to use bind variables with the ORDER BY clause.

How to check the validity of the dateformat (ex, %d/%m/%Y-%H:%M:%S)?

I am using boost optionsparser to parse the command-line arguments passed by the user.
Now the program had an option for the user to specify his/her choice of dateformat.
like,
program -d %d/%m/%Y-%H:%M:%S , program -d %d/%m/%Y and so on.
The problem I am facing is, *How do I check the validity of the format string passed by the user? *
The only way I can think of now is passing the format string on to the date class and using the exception handling there.
However, if there is another way to check the validity at the time of parsing the options then I wouldn't need to pass around the data and do stuff unncessarily since I do some calculation before actually using the format to generate the date string.
I wouldn't need to pass around the data and do stuff unncessarily since I do some calculation before actually using the format to generate the date string.
Instead of jumping through hoops to calculate something to pass to the date class to validate the format string, why don't you just ask the date class to format today's date for you and see if it generates an exception or not?
If you try to parse it yourself you're just writing code that's duplicating what the date class does, but that also has the chance of missing some detail. You may annoy your user by disallowing something that should be allowed (I've had this happen with applications that tell me my perfectly valid email isn't), and you'll have to handle the exception from the date class anyway in case you don't cover all the bases that it covers when parsing the format