Permalink
Browse files

Merge pull request #2 from dcepler/master

Fixed Canonicalize, added Functions, and Unit Testing
  • Loading branch information...
2 parents a0f68e9 + 8d83447 commit b5caa475b06d17e6d59ab9bb03f5e9095399a3aa @misterdai committed Jul 9, 2012
Showing with 678 additions and 58 deletions.
  1. +31 −5 README
  2. +198 −53 cf10.cfm
  3. +19 −0 cf9.cfm
  4. +3 −0 cfbackport.cfm
  5. +7 −0 test/Application.cfc
  6. +16 −0 test/TestSuite.cfm
  7. +404 −0 test/cfbackportTest.cfc
View
36 README
@@ -8,8 +8,8 @@
Author: David "Mister Dai" Boyer
Website: http://misterdai.wordpress.com
-Version: 0.6
-Contributors: Henry Ho
+Version: 0.7
+Contributors: Henry Ho, David Epler
----------------------
| Description |
@@ -30,6 +30,12 @@ aren't loaded if the version already supports them.
Functions should work in at least ColdFusion 8+. Where possible I've tried to
avoid using newer syntax or functions
+If ColdFusion is patched with APSB11-04 or higher, ESAPI is available for
+Encode and Decode functions.
+
+APSB11-04+ installs ESAPI 1.4.4 for CF8.0.x and ESAPI 2.0_rc10 for CF9.0.0/1
+CF9.0.2 already has ESAPI 2.0_rc10 installed
+
----------------------
| Usage |
----------------------
@@ -44,21 +50,41 @@ there to make use of them.
| Functions |
----------------------
- * Backported from CF10
+ * Backported from CF10 for CF9 and CF8
ArraySlice
CallStackDump
CallStackGet
- Canoncicalize
+ Canonicalize
CsrfGenerateToken
CsrfVerifyToken
+ DecodeForHTML (David Epler) [requires ESAPI 2.0+]
+ DecodeFromURL (David Epler)
EncodeForCSS (Henry Ho)
EncodeForHTML
EncodeForHTMLAttribute (Henry Ho)
EncodeForJavaScript (Henry Ho)
EncodeForURL (Henry Ho)
+ EncodeForXML (David Epler)
GetApplicationMetadata
+ HMac (David Epler)
IsClosure
ReEscape
SessionInvalidate
- SessionStartTime
+ SessionStartTime
+
+ * Backported from CF9 for CF8
+ throw (David Epler) [required for DecodeFromURL]
+
+----------------------
+| Unit Tests |
+----------------------
+
+Unit tests were created with MXUnit 2.1.1
+
+ * As written (of course) CF10 passes them all
+ * CF9.0.x with APSB11-04+ - 13 success, 0 error, 1 failure
+ * Failure is due to ESAPI version difference
+ * CF8.0.x with APSB11-04+ - 9 success, 1 error, 4 failure
+ * Failure and Error is due to ESAPI version difference
+
View
251 cf10.cfm
@@ -196,81 +196,226 @@
<cfreturn ReReplace(arguments.string, "([\[\]\(\)\^\$\.\+\?\*\-\|])", "\$1", "all") />
</cffunction>
-<cffunction name="Canoncicalize" output="false" returntype="string">
- <cfargument name="inputString" type="string" required="true" />
- <cfargument name="restrictMultiple" type="boolean" required="true" />
- <cfargument name="restrictMixed" type="boolean" required="true" />
- <cfreturn CreateObject("java", "org.owasp.esapi.ESAPI").encoder().canonicalize(arguments.string, arguments.restrictMultiple, arguments.restrictMixed) />
+<cffunction name="Canonicalize" output="false" returntype="string" hint="Canonicalize or decode the input string, returns Decoded form of input string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to be encode" />
+ <cfargument name="restrictMultiple" type="boolean" required="true" hint="Required. If set to true, multiple encoding is restricted" />
+ <cfargument name="restrictMixed" type="boolean" required="true" hint="Required. If set to true, mixed encoding is restricted (Ignored with ESAPI <2.0.0)" />
+
+ <cfscript>
+ var lc = StructNew();
+ var canonicalizedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+
+ /*
+ * ESAPI 2.0.0+ (r1630) supports String canonicalize( String input, boolean restrictMultiple, boolean restrictMixed )
+ * unfortunately APSB11-04+ installs ESAPI 1.4.4 for CF8.0.x and ESAPI 2.0_rc10 for CF9.0.x and CF9.0.2 which don't have it
+ * try ESAPI 2.0.0+ call then fall back
+ */
+ try {
+ canonicalizedString = lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.restrictMultiple), JavaCast("boolean", arguments.restrictMixed));
+ }
+ catch(Any excpt) {
+ canonicalizedString = lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.restrictMultiple));
+ }
+
+ return canonicalizedString;
+ </cfscript>
</cffunction>
-<cffunction name="EncodeForCSS" output="false" returntype="string">
- <cfargument name="inputString" type="string" required="true" />
- <cfargument name="strict" type="boolean" required="false" default="false" />
- <cfscript>
- var lc = StructNew();
- lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
- return lc.encoder.encodeForCSS(lc.encoder.canoncicalize(arguments.inputString, arguments.strict));
- </cfscript>
+<cffunction name="EncodeForCSS" output="false" returntype="string" hint="Encodes the input string for use in CSS, returns Encoded string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to encode" />
+ <cfargument name="strict" type="boolean" default="false" hint="Optional. If set to true, restricts multiple and mixed encoding" />
+
+ <cfscript>
+ var lc = StructNew();
+ var encodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ encodedString = lc.encoder.encodeForCSS(lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.strict)));
+
+ return encodedString;
+ </cfscript>
</cffunction>
-<cffunction name="EncodeForHTML" output="false" returntype="string">
- <cfargument name="inputString" type="string" required="true" />
- <cfargument name="strict" type="boolean" required="false" default="false" />
- <cfscript>
- var lc = StructNew();
- lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
- return lc.encoder.encodeForHTML(lc.encoder.canoncicalize(arguments.inputString, arguments.strict));
- </cfscript>
+<cffunction name="DecodeForHTML" output="false" returntype="string" hint="Decodes an HTML encoded string, returns Decoded HTML string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. Encoded string to decode" />
+
+ <cfscript>
+ var lc = StructNew();
+ var decodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ decodedString = lc.encoder.DecodeForHTML(JavaCast("string", arguments.inputString));
+
+ return decodedString;
+ </cfscript>
</cffunction>
-<cffunction name="EncodeForHTMLAttribute" output="false" returntype="string">
- <cfargument name="inputString" type="string" required="true" />
- <cfargument name="strict" type="boolean" required="false" default="false" />
- <cfscript>
- var lc = StructNew();
- lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
- return lc.encoder.encodeForHTMLAttribute(lc.encoder.canoncicalize(arguments.inputString, arguments.strict));
- </cfscript>
+<cffunction name="EncodeForHTML" output="false" returntype="string" hint="Encodes the input string for use in HTML, returns Encoded string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to encode" />
+ <cfargument name="strict" type="boolean" default="false" hint="Optional. If set to true, restricts multiple and mixed encoding" />
+
+ <cfscript>
+ var lc = StructNew();
+ var encodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ encodedString = lc.encoder.encodeForHTML(lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.strict)));
+
+ return encodedString;
+ </cfscript>
</cffunction>
-<cffunction name="EncodeForJavaScript" output="false" returntype="string">
- <cfargument name="inputString" type="string" required="true" />
- <cfargument name="strict" type="boolean" required="false" default="false" />
- <cfscript>
- var lc = StructNew();
- lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
- return lc.encoder.encodeForJavaScript(lc.encoder.canoncicalize(arguments.inputString, arguments.strict));
- </cfscript>
+<cffunction name="EncodeForHTMLAttribute" output="false" returntype="string" hint="Encodes the input string for use in HTML attribute, returns Encoded string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to encode" />
+ <cfargument name="strict" type="boolean" default="false" hint="Optional. If set to true, restricts multiple and mixed encoding" />
+
+ <cfscript>
+ var lc = StructNew();
+ var encodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ encodedString = lc.encoder.encodeForHTMLAttribute(lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.strict)));
+
+ return encodedString;
+ </cfscript>
</cffunction>
-<cffunction name="EncodeForURL" output="false" returntype="string">
- <cfargument name="inputString" type="string" required="true" />
- <cfargument name="strict" type="boolean" required="false" default="false" />
- <cfscript>
- var lc = StructNew();
- lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
- return lc.encoder.encodeForURL(lc.encoder.canoncicalize(arguments.inputString, arguments.strict));
- </cfscript>
+<cffunction name="EncodeForJavaScript" output="false" returntype="string" hint="Encodes the input string for use in JavaScript, returns Encoded string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to encode" />
+ <cfargument name="strict" type="boolean" default="false" hint="Optional. If set to true, restricts multiple and mixed encoding" />
+
+ <cfscript>
+ var lc = StructNew();
+ var encodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ encodedString = lc.encoder.encodeForJavaScript(lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.strict)));
+
+ return encodedString;
+ </cfscript>
+</cffunction>
+
+
+<cffunction name="DecodeFromURL" output="false" returntype="string" hint="">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to decode" />
+
+ <cfscript>
+ var lc = StructNew();
+
+ local.encoding = createObject("java", "java.lang.System").getProperty("file.encoding");
+ try {
+ return createObject("java", "java.net.URLDecoder").decode(javaCast("string", canonicalize(arguments.inputString, false, false)), local.encoding);
+ }
+ // throw the same errors as CF10
+ catch(java.io.UnsupportedEncodingException ex) {
+ // Character encoding not supported
+ throw("There was an error while encoding.", "Application", "For more details check logs.");
+ }
+ catch(java.lang.Exception e) {
+ // Problem URL decoding input
+ throw("There was an error while encoding.", "Application", "For more details check logs.");
+ }
+ </cfscript>
+
+ </cffunction>
+
+
+<cffunction name="EncodeForURL" output="false" returntype="string" hint="Encodes the input string for use in URLs, returns Encoded string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to encode" />
+ <cfargument name="strict" type="boolean" default="false" hint="Optional. If set to true, restricts multiple and mixed encoding" />
+
+ <cfscript>
+ var lc = StructNew();
+ var encodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ encodedString = lc.encoder.encodeForURL(lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.strict)));
+
+ return encodedString;
+ </cfscript>
+</cffunction>
+
+<cffunction name="EncodeForXML" output="false" returntype="string" hint="Encodes the input string for use in XML, returns Encoded string">
+ <cfargument name="inputString" type="string" required="true" hint="Required. String to encode" />
+ <cfargument name="strict" type="boolean" default="false" hint="Optional. If set to true, restricts multiple and mixed encoding" />
+
+ <cfscript>
+ var lc = StructNew();
+ var encodedString = "";
+
+ lc.encoder = CreateObject("java", "org.owasp.esapi.ESAPI").encoder();
+ encodedString = lc.encoder.encodeForXML(lc.encoder.canonicalize(JavaCast("string", arguments.inputString), JavaCast("boolean", arguments.strict)));
+
+ return encodedString;
+ </cfscript>
+</cffunction>
+
+<!---
+Based upon code from http://www.coldfusiondeveloper.com.au/go/note/2008/01/18/hmac-sha1-using-java/
+ --->
+<cffunction name="HMac" output="false" returntype="string" description="Creates Hash-based Message Authentication Code for the given string or byte array based on the algorithm and encoding">
+ <cfargument name="message" type="any" required="true" hint="can be string or byte array" />
+ <cfargument name="key" type="any" required="true" hint="can be string or byte array" />
+ <cfargument name="algorithm" type="string" default="HMACMD5" hint="HMACMD5, HMACSHA1, HMACSHA256, HMACSHA384, HMACSHA512, HMACRIPEMD160, HMACSHA224" />
+ <cfargument name="encoding" type="string" default="#createObject('java', 'java.lang.System').getProperty('file.encoding')#" hint="encoding to use" />
+
+ <cfset var byteArray = {} />
+ <cfset var javaObject = {} />
+
+ <cfif NOT IsBinary(arguments.message)>
+ <cfset byteArray.Message = CharsetDecode(arguments.message, arguments.encoding) />
+ <cfelse>
+ <cfset byteArray.Message = arguments.message />
+ </cfif>
+
+ <cfif NOT IsBinary(arguments.key)>
+ <cfset byteArray.Key = CharsetDecode(arguments.key, arguments.encoding) />
+ <cfelse>
+ <cfset byteArray.Key = arguments.key />
+ </cfif>
+
+ <cfset javaObject.Key = createObject("java","javax.crypto.spec.SecretKeySpec").init(byteArray.Key, arguments.algorithm) />
+ <cfset javaObject.Mac = createObject("java","javax.crypto.Mac") />
+
+ <cfset javaObject.Mac = javaObject.Mac.getInstance(arguments.algorithm) />
+ <cfset javaObject.Mac.init(javaObject.Key) />
+
+ <cfreturn BinaryEncode(javaObject.Mac.doFinal(byteArray.Message), "hex") />
</cffunction>
<!---
- ESAPI library requires CF9.0.1+ or have the library added manually.
+ Hopefully, ColdFusion is patched and therefore ESAPI is available
+ APSB11-04+ installs ESAPI 1.4.4 for CF8.0.x and ESAPI 2.0_rc10 for CF9.0.x and CF9.0.2
- Function tags cannot be wrapped in "if" statements to exclude creation.
- Instead, test for the required ESAPI class and destroy if missing.
+ Test for ESAPI existance by calling canonicalize, if exception is thrown
+ remove the functions that are dependent upon it
--->
-<cfset cfbackport.temp = ArrayNew(1) />
<cftry>
- <!--- If the Java class doesn't exist, catch the exception --->
- <cfset cfbackport.temp.getClass().forName("org.owasp.esapi.ESAPI", false, JavaCast("null", "")) />
+ <cfset canonicalize("", false, false) />
+
<cfcatch type="any">
- <cfset StructDelete(variables, "Canoncicalize") />
+ <cfset StructDelete(variables, "Canonicalize") />
+ <cfset StructDelete(variables, "DecodeFromURL") />
<cfset StructDelete(variables, "EncodeForCSS") />
<cfset StructDelete(variables, "EncodeForHTML") />
<cfset StructDelete(variables, "EncodeForHTMLAttribute") />
<cfset StructDelete(variables, "EncodeForJavaScript") />
<cfset StructDelete(variables, "EncodeForURL") />
+ <cfset StructDelete(variables, "EncodeForXML") />
+ </cfcatch>
+</cftry>
+
+<!---
+ ESAPI 1.4.4 does not have DecodeForHTML
+ --->
+<cftry>
+ <cfset decodeForHTML("") />
+
+ <cfcatch type="any">
+ <cfset StructDelete(variables, "DecodeForHTML") />
</cfcatch>
</cftry>
-<cfset StructDelete(variables, "cfbackport") />
+<cfset StructDelete(variables, "cfbackport") />
View
19 cf9.cfm
@@ -0,0 +1,19 @@
+
+<!---
+Based upon http://cflib.org/udf/Throw, modified to match CF9 throw() argument order
+--->
+<cffunction returnType="void" name="throw" output="false" hint="CFML Throw wrapper">
+ <cfargument name="message" type="string" default="" hint="Message for Exception">
+ <cfargument name="type" type="string" default="Application" hint="Type for Exception">
+ <cfargument name="detail" type="string" default="" hint="Detail for Exception">
+ <cfargument name="errorCode" type="string" default="" hint="Error Code for Exception">
+ <cfargument name="extendedInfo" type="string" default="" hint="Extended Info for Exception">
+ <cfargument name="object" type="any" hint="Object for Exception">
+
+ <cfif NOT IsDefined("arguments.object")>
+ <cfthrow message="#arguments.message#" type="#arguments.type#" detail="#arguments.detail#" errorCode="#arguments.errorCode#" extendedInfo="#arguments.extendedInfo#">
+ <cfelse>
+ <cfthrow object="#arguments.object#">
+ </cfif>
+
+</cffunction>
View
@@ -4,6 +4,9 @@
cfbackport.major = ListFirst(server.coldfusion.productVersion);
cfbackport.minor = ListFirst(Replace(ListDeleteAt(server.coldfusion.productVersion, 1), ",", "."));
</cfscript>
+ <cfif cfbackport.major lt 9>
+ <cfinclude template="cf9.cfm" />
+ </cfif>
<cfif cfbackport.major lt 10>
<cfinclude template="cf10.cfm" />
</cfif>
View
@@ -0,0 +1,7 @@
+<cfcomponent output="false">
+
+ <cfscript>
+ this.name = "cfbackport" & hash(getCurrentTemplatePath());
+ </cfscript>
+
+</cfcomponent>
Oops, something went wrong.

0 comments on commit b5caa47

Please sign in to comment.