One important task for connecting to the GoGrid API is calculating your signature. From their documentation, this is calculated by:
"generating an MD5 hash made up by concatenating the API key, the API user's shared secret, and a UNIX timestamp reflecting the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) when the request is made."
The keyword in this definition is: seconds since the Unix Epoch.
Unfortunately, I did not read this definition closely, and naively translated my already working Python implementation:
import md5
import time
class GoGridClient:
"""sample gogrid api client"""
api_key = 'xxxxxxxxxxx'
secret = 'someonesSecret'
....
def getSignature(self,key,secret):
""" create sig from md5 of key + secret + time """
m = md5.new(key+secret+str(int(time.time())))
return m.hexdigest()
to the following Scala implementation, with a little help from Code Redefined's post for calculating the MD5 sum in Scala:
import java.security.MessageDigest
object BrokenClient {
val apiKey = "xxxxxxxxxxx"
val apiSecret = "someonesSecret"
val apiSignature: String = {
// m = md5.new(key+secret+str(int(time.time())))
val signature = MessageDigest.getInstance("MD5")
val timeStamp = System.currentTimeMillis().toString //<-- WRONG!!!!
signature.update(apiKey.getBytes)
signature.update(apiSecret.getBytes)
signature.update(timeStamp.getBytes)
signature.digest().map(0xFF & _).map { "%02x".format(_) }.foldLeft("") { _ + _ }
}
}
And sadly kept getting a 403: Authentication Failed error. The correct way to implement this is:
import java.security.MessageDigest
object BrokenClient {
val apiKey = "xxxxxxxxxxx"
val apiSecret = "someonesSecret"
val apiSignature: String = {
// m = md5.new(key+secret+str(int(time.time())))
val signature = MessageDigest.getInstance("MD5")
val timeStamp = ((java.util.Calendar.getInstance(TimeZone.getTimeZone("GMT-0:00")).getTimeInMillis()) / 1000).toString //<-- YAY ^_^
signature.update(apiKey.getBytes)
signature.update(apiSecret.getBytes)
signature.update(timeStamp.getBytes)
signature.digest().map(0xFF & _).map { "%02x".format(_) }.foldLeft("") { _ + _ }
}
}
Note that there is some kinda weirdness going on, in that timeStamp works even if you don't pass in a time zone, or if you pass in a random time zone.
No comments:
Post a Comment