I was taking training on Struts 2, which involved importing some existing "Lab" projects into my Eclipse environment. Everything went smoothly the first time I ran the project, but after making updates and re-running the project, the server would not reflect any of my changes!
For hours, myself and a more senior developer banged our heads trying to figure out this problem. We installed a different version of Tomcat, cleaned the project and the working directory, cleared cache, etc. and nothing worked! From simple outputs to the console in class files, to adding or renaming actions in struts.xml, the project always executed as if it were the first run.
Per usual, the most troubling problem had the simplest solution. The person who originally created the project had the JRE imported from an unusual location. Upon import, I received errors saying java and javax could not be resolved. I hovered over an import statement, and used the "Fix project setup..." option to automatically add Eclipse's default JRE to the build path.
Though it properly added the JRE, it did not remove the old JRE location from the build path. Apparently this can cause some very mysterious behavior... As a last resort we checked the build path, and removed the bad JRE. Problem solved! Everything began functioning as expected.
Noobs using Eclipse Indigo: Right click on the project and select Build Path > Configure Build Path.... Under the Libraries tab, see if you have two JRE libraries. If so, delete the one with the little red X.
Thursday, June 13, 2013
Sunday, March 3, 2013
Google Maps API for Business: Signing a URL in ColdFusion (Example)
This is one of those problems that quickly sucked up a majority of my day... I wanted to use ColdFusion to make HTTP geocoding requests to the Google Maps API using my employer's business license for the service. Try as I might, using ColdFusion's encryption functions to mimic the other examples kept returning garbage.
But then it dawned on me, the Java example could be mimicked to the T in ColdFusion, since it runs on the Java platform!
But then it dawned on me, the Java example could be mimicked to the T in ColdFusion, since it runs on the Java platform!
<cffunction name="signGoogleURL">
<cfargument name="url" />
<!--- I stored the key in the request scope, you can remove the default attribute --->
<cfargument name="key" default="#request.GoogleAPIs.mapsV3.cryptoKey#" />
<cfset var local = {} />
<cfif Find(".googleapis.com", arguments.url) EQ 0>
<cfthrow message="Invalid Google URL." />
</cfif>
<!--- pull off the googleapis piece of the URL --->
<cfset local.urlToEncrypt =
Right(arguments.url,
Len(arguments.url)-(Find(".googleapis.com", arguments.url)+14)
)
/>
<!--- this is the part we encrypt and pass as signature --->
<cfset local.msg_digest = cfhmac(local.urlToEncrypt, webSafeToBase64(arguments.key)) />
<cfreturn arguments.url & "&signature="
& Base64ToWebSafe(local.msg_digest) />
</cffunction>
<!--- this function mimmicks the code in signRequest from the Java example --->
<cffunction name="CFHMAC" output="false">
<cfargument name="signMsg" type="string" required="true" />
<cfargument name="signKey" type="string" required="true" />
<cfset var local = {} />
<!--- get the key in binary --->
<cfset local.key = BinaryDecode(arguments.signKey, "base64") />
<!--- initialize the crypto object with the key and algorithm --->
<cfset local.keySpec = createObject("java", "javax.crypto.spec.SecretKeySpec").init(local.key, "HmacSHA1") />
<cfset local.mac = createObject("java", "javax.crypto.Mac").getInstance("HmacSHA1") />
<cfset local.mac.init(local.keySpec) />
<!--- pass the message's bytes into the crypto object. we return it in Base64 --->
<cfreturn ToBase64(
local.mac.doFinal(arguments.signMsg.getBytes())
) />
</cffunction>
<!--- simple switch from google's webSafe format to the actual Base64, in the Java example this is done in UrlSigner() --->
<cffunction name="webSafeToBase64">
<cfargument name="val" />
<cfset arguments.val = replace(
replace(arguments.val, "-", "+", "ALL")
, "_", "/", "ALL") />
<cfreturn arguments.val />
</cffunction>
<!--- switch back to google's format, before adding to URL. In the Java example this is done at the bottom of signRequest() --->
<cffunction name="Base64ToWebSafe">
<cfargument name="val" />
<cfset arguments.val = replace(
replace(arguments.val, "+", "-", "ALL")
, "/", "_", "ALL") />
<cfreturn arguments.val />
</cffunction>
I chose to include these in a component, and call it as follows:
<cfset variables.requestURL = Maps.signGoogleUrl([url], [API CryptoKey]) />The url variable is the full googleapis address including the protocol, and URL parameters like the required client variable. You can then pass that into a cfhttp call and your requests will be validated by your client and cryptoKey values! Hope this saves somebody some time, let me know if you find it useful!
Subscribe to:
Posts (Atom)