Reputation: 61
I'm writing a script of OAuth in Python.
For testing this, I use Twitter API. But it is not working well.
def test():
params = {
"oauth_consumer_key": TWITTER_OAUTH_CONSUMER_KEY,
"oauth_nonce": "".join(random.choice(string.digits + string.letters) for i in xrange(7)),
"oauth_signature_method": "HMAC-SHA1",
"oauth_timestamp": str(int(time.time())),
"oauth_token": res_dict["oauth_token"],
"oauth_version": "1.0",
}
status = {"status": u"Always_look_on_the_bright_side_of_life".encode("UTF-8")}
print status
params.update(status)
url = "http://twitter.com/statuses/update.xml"
key = "&".join([TWITTER_OAUTH_CONSUMER_SECRET, res_dict["oauth_token_secret"]])
msg = "&".join(["POST", urllib.quote(url,""),
urllib.quote("&".join([k+"="+params[k] for k in sorted(params)]), "-._~")])
print msg
signature = hmac.new(key, msg, hashlib.sha1).digest().encode("base64").strip()
params["oauth_signature"] = signature
req = urllib2.Request(url,
headers={"Authorization":"OAuth", "Content-type":"application/x-www-form-urlencoded"})
req.add_data("&".join([k+"="+urllib.quote(params[k], "-._~") for k in params]))
print req.get_data()
res = urllib2.urlopen(req).read()
print res
This script (status="Always_look_on_the_bright_side_of_life") is working.
But, in case status is "Always look on the bright side of life"(replaced underscore with space), it isn't working(is returning HTTP Error 401: Unauthorized).
I referenced this question, but failed.
Please give me some advice. Thank you.
Upvotes: 4
Views: 1428
Reputation: 3020
I got the same problem in OAuth with FaceBook a while ago. The problem is that the signature validation on server side fails. See your signature generation code here:
msg = "&".join(["POST", urllib.quote(url,""),
urllib.quote("&".join([k+"="+params[k] for k in sorted(params)]), "-._~")])
print msg
signature = hmac.new(key, msg, hashlib.sha1).digest().encode("base64").strip()
It uses the raw (non-encoded) form of the string to generate the signature. However, the server side generates validates the signature against the URL quoted string:
req.add_data("&".join([k+"="+urllib.quote(params[k], "-._~") for k in params]))
To fix the code, you need to do fix this line by creating the signature from the url encoded parameter:
msg = "&".join(["POST", urllib.quote(url,""),
urllib.quote("&".join([k+"="+urllib.quote(params[k], "-._~") for k in sorted(params)]), "-._~")])
Upvotes: 1
Reputation:
The easiest way to fix this is to add status = urllib.quote(status)
after status = {"status": u"Always_look_on_the_bright_side_of_life".encode("UTF-8")}
. This will escape the spaces and other special characters as required.
Upvotes: 0