Update Tornado lib
This commit is contained in:
+77
-36
@@ -50,7 +50,6 @@ import base64
|
||||
import binascii
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
import time
|
||||
import urllib
|
||||
import urlparse
|
||||
@@ -59,6 +58,7 @@ import uuid
|
||||
from tornado import httpclient
|
||||
from tornado import escape
|
||||
from tornado.httputil import url_concat
|
||||
from tornado.log import gen_log
|
||||
from tornado.util import bytes_type, b
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class OpenIdMixin(object):
|
||||
args["openid.mode"] = u"check_authentication"
|
||||
url = self._OPENID_ENDPOINT
|
||||
if http_client is None:
|
||||
http_client = httpclient.AsyncHTTPClient()
|
||||
http_client = self.get_auth_http_client()
|
||||
http_client.fetch(url, self.async_callback(
|
||||
self._on_authentication_verified, callback),
|
||||
method="POST", body=urllib.urlencode(args))
|
||||
@@ -150,7 +150,7 @@ class OpenIdMixin(object):
|
||||
|
||||
def _on_authentication_verified(self, callback, response):
|
||||
if response.error or b("is_valid:true") not in response.body:
|
||||
logging.warning("Invalid OpenID response: %s", response.error or
|
||||
gen_log.warning("Invalid OpenID response: %s", response.error or
|
||||
response.body)
|
||||
callback(None)
|
||||
return
|
||||
@@ -203,8 +203,19 @@ class OpenIdMixin(object):
|
||||
user["locale"] = locale
|
||||
if username:
|
||||
user["username"] = username
|
||||
claimed_id = self.get_argument("openid.claimed_id", None)
|
||||
if claimed_id:
|
||||
user["claimed_id"] = claimed_id
|
||||
callback(user)
|
||||
|
||||
def get_auth_http_client(self):
|
||||
"""Returns the AsyncHTTPClient instance to be used for auth requests.
|
||||
|
||||
May be overridden by subclasses to use an http client other than
|
||||
the default.
|
||||
"""
|
||||
return httpclient.AsyncHTTPClient()
|
||||
|
||||
|
||||
class OAuthMixin(object):
|
||||
"""Abstract implementation of OAuth.
|
||||
@@ -229,7 +240,7 @@ class OAuthMixin(object):
|
||||
if callback_uri and getattr(self, "_OAUTH_NO_CALLBACKS", False):
|
||||
raise Exception("This service does not support oauth_callback")
|
||||
if http_client is None:
|
||||
http_client = httpclient.AsyncHTTPClient()
|
||||
http_client = self.get_auth_http_client()
|
||||
if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a":
|
||||
http_client.fetch(
|
||||
self._oauth_request_token_url(callback_uri=callback_uri,
|
||||
@@ -260,21 +271,21 @@ class OAuthMixin(object):
|
||||
oauth_verifier = self.get_argument("oauth_verifier", None)
|
||||
request_cookie = self.get_cookie("_oauth_request_token")
|
||||
if not request_cookie:
|
||||
logging.warning("Missing OAuth request token cookie")
|
||||
gen_log.warning("Missing OAuth request token cookie")
|
||||
callback(None)
|
||||
return
|
||||
self.clear_cookie("_oauth_request_token")
|
||||
cookie_key, cookie_secret = [base64.b64decode(escape.utf8(i)) for i in request_cookie.split("|")]
|
||||
if cookie_key != request_key:
|
||||
logging.info((cookie_key, request_key, request_cookie))
|
||||
logging.warning("Request token does not match cookie")
|
||||
gen_log.info((cookie_key, request_key, request_cookie))
|
||||
gen_log.warning("Request token does not match cookie")
|
||||
callback(None)
|
||||
return
|
||||
token = dict(key=cookie_key, secret=cookie_secret)
|
||||
if oauth_verifier:
|
||||
token["verifier"] = oauth_verifier
|
||||
if http_client is None:
|
||||
http_client = httpclient.AsyncHTTPClient()
|
||||
http_client = self.get_auth_http_client()
|
||||
http_client.fetch(self._oauth_access_token_url(token),
|
||||
self.async_callback(self._on_access_token, callback))
|
||||
|
||||
@@ -282,14 +293,16 @@ class OAuthMixin(object):
|
||||
consumer_token = self._oauth_consumer_token()
|
||||
url = self._OAUTH_REQUEST_TOKEN_URL
|
||||
args = dict(
|
||||
oauth_consumer_key=consumer_token["key"],
|
||||
oauth_consumer_key=escape.to_basestring(consumer_token["key"]),
|
||||
oauth_signature_method="HMAC-SHA1",
|
||||
oauth_timestamp=str(int(time.time())),
|
||||
oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
|
||||
oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)),
|
||||
oauth_version=getattr(self, "_OAUTH_VERSION", "1.0a"),
|
||||
)
|
||||
if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a":
|
||||
if callback_uri:
|
||||
if callback_uri == "oob":
|
||||
args["oauth_callback"] = "oob"
|
||||
elif callback_uri:
|
||||
args["oauth_callback"] = urlparse.urljoin(
|
||||
self.request.full_url(), callback_uri)
|
||||
if extra_params:
|
||||
@@ -309,7 +322,10 @@ class OAuthMixin(object):
|
||||
base64.b64encode(request_token["secret"]))
|
||||
self.set_cookie("_oauth_request_token", data)
|
||||
args = dict(oauth_token=request_token["key"])
|
||||
if callback_uri:
|
||||
if callback_uri == "oob":
|
||||
self.finish(authorize_url + "?" + urllib.urlencode(args))
|
||||
return
|
||||
elif callback_uri:
|
||||
args["oauth_callback"] = urlparse.urljoin(
|
||||
self.request.full_url(), callback_uri)
|
||||
self.redirect(authorize_url + "?" + urllib.urlencode(args))
|
||||
@@ -318,11 +334,11 @@ class OAuthMixin(object):
|
||||
consumer_token = self._oauth_consumer_token()
|
||||
url = self._OAUTH_ACCESS_TOKEN_URL
|
||||
args = dict(
|
||||
oauth_consumer_key=consumer_token["key"],
|
||||
oauth_token=request_token["key"],
|
||||
oauth_consumer_key=escape.to_basestring(consumer_token["key"]),
|
||||
oauth_token=escape.to_basestring(request_token["key"]),
|
||||
oauth_signature_method="HMAC-SHA1",
|
||||
oauth_timestamp=str(int(time.time())),
|
||||
oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
|
||||
oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)),
|
||||
oauth_version=getattr(self, "_OAUTH_VERSION", "1.0a"),
|
||||
)
|
||||
if "verifier" in request_token:
|
||||
@@ -340,7 +356,7 @@ class OAuthMixin(object):
|
||||
|
||||
def _on_access_token(self, callback, response):
|
||||
if response.error:
|
||||
logging.warning("Could not fetch access token")
|
||||
gen_log.warning("Could not fetch access token")
|
||||
callback(None)
|
||||
return
|
||||
|
||||
@@ -367,11 +383,11 @@ class OAuthMixin(object):
|
||||
"""
|
||||
consumer_token = self._oauth_consumer_token()
|
||||
base_args = dict(
|
||||
oauth_consumer_key=consumer_token["key"],
|
||||
oauth_token=access_token["key"],
|
||||
oauth_consumer_key=escape.to_basestring(consumer_token["key"]),
|
||||
oauth_token=escape.to_basestring(access_token["key"]),
|
||||
oauth_signature_method="HMAC-SHA1",
|
||||
oauth_timestamp=str(int(time.time())),
|
||||
oauth_nonce=binascii.b2a_hex(uuid.uuid4().bytes),
|
||||
oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)),
|
||||
oauth_version=getattr(self, "_OAUTH_VERSION", "1.0a"),
|
||||
)
|
||||
args = {}
|
||||
@@ -386,6 +402,14 @@ class OAuthMixin(object):
|
||||
base_args["oauth_signature"] = signature
|
||||
return base_args
|
||||
|
||||
def get_auth_http_client(self):
|
||||
"""Returns the AsyncHTTPClient instance to be used for auth requests.
|
||||
|
||||
May be overridden by subclasses to use an http client other than
|
||||
the default.
|
||||
"""
|
||||
return httpclient.AsyncHTTPClient()
|
||||
|
||||
|
||||
class OAuth2Mixin(object):
|
||||
"""Abstract implementation of OAuth v 2."""
|
||||
@@ -463,6 +487,7 @@ class TwitterMixin(OAuthMixin):
|
||||
_OAUTH_AUTHORIZE_URL = "http://api.twitter.com/oauth/authorize"
|
||||
_OAUTH_AUTHENTICATE_URL = "http://api.twitter.com/oauth/authenticate"
|
||||
_OAUTH_NO_CALLBACKS = False
|
||||
_TWITTER_BASE_URL = "http://api.twitter.com/1"
|
||||
|
||||
def authenticate_redirect(self, callback_uri=None):
|
||||
"""Just like authorize_redirect(), but auto-redirects if authorized.
|
||||
@@ -470,7 +495,7 @@ class TwitterMixin(OAuthMixin):
|
||||
This is generally the right interface to use if you are using
|
||||
Twitter for single-sign on.
|
||||
"""
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
http.fetch(self._oauth_request_token_url(callback_uri=callback_uri), self.async_callback(
|
||||
self._on_request_token, self._OAUTH_AUTHENTICATE_URL, None))
|
||||
|
||||
@@ -517,7 +542,7 @@ class TwitterMixin(OAuthMixin):
|
||||
# usual pattern: http://search.twitter.com/search.json
|
||||
url = path
|
||||
else:
|
||||
url = "http://api.twitter.com/1" + path + ".json"
|
||||
url = self._TWITTER_BASE_URL + path + ".json"
|
||||
# Add the OAuth resource request signature if we have credentials
|
||||
if access_token:
|
||||
all_args = {}
|
||||
@@ -530,7 +555,7 @@ class TwitterMixin(OAuthMixin):
|
||||
if args:
|
||||
url += "?" + urllib.urlencode(args)
|
||||
callback = self.async_callback(self._on_twitter_request, callback)
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
if post_args is not None:
|
||||
http.fetch(url, method="POST", body=urllib.urlencode(post_args),
|
||||
callback=callback)
|
||||
@@ -539,7 +564,7 @@ class TwitterMixin(OAuthMixin):
|
||||
|
||||
def _on_twitter_request(self, callback, response):
|
||||
if response.error:
|
||||
logging.warning("Error response %s fetching %s", response.error,
|
||||
gen_log.warning("Error response %s fetching %s", response.error,
|
||||
response.request.url)
|
||||
callback(None)
|
||||
return
|
||||
@@ -555,7 +580,7 @@ class TwitterMixin(OAuthMixin):
|
||||
def _oauth_get_user(self, access_token, callback):
|
||||
callback = self.async_callback(self._parse_user_response, callback)
|
||||
self.twitter_request(
|
||||
"/users/show/" + access_token["screen_name"],
|
||||
"/users/show/" + escape.native_str(access_token[b("screen_name")]),
|
||||
access_token=access_token, callback=callback)
|
||||
|
||||
def _parse_user_response(self, callback, user):
|
||||
@@ -652,7 +677,7 @@ class FriendFeedMixin(OAuthMixin):
|
||||
if args:
|
||||
url += "?" + urllib.urlencode(args)
|
||||
callback = self.async_callback(self._on_friendfeed_request, callback)
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
if post_args is not None:
|
||||
http.fetch(url, method="POST", body=urllib.urlencode(post_args),
|
||||
callback=callback)
|
||||
@@ -661,7 +686,7 @@ class FriendFeedMixin(OAuthMixin):
|
||||
|
||||
def _on_friendfeed_request(self, callback, response):
|
||||
if response.error:
|
||||
logging.warning("Error response %s fetching %s", response.error,
|
||||
gen_log.warning("Error response %s fetching %s", response.error,
|
||||
response.request.url)
|
||||
callback(None)
|
||||
return
|
||||
@@ -743,7 +768,7 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
|
||||
break
|
||||
token = self.get_argument("openid." + oauth_ns + ".request_token", "")
|
||||
if token:
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
token = dict(key=token, secret="")
|
||||
http.fetch(self._oauth_access_token_url(token),
|
||||
self.async_callback(self._on_access_token, callback))
|
||||
@@ -854,7 +879,7 @@ class FacebookMixin(object):
|
||||
self._on_get_user_info, callback, session),
|
||||
session_key=session["session_key"],
|
||||
uids=session["uid"],
|
||||
fields="uid,first_name,last_name,name,locale,pic_square," \
|
||||
fields="uid,first_name,last_name,name,locale,pic_square,"
|
||||
"profile_url,username")
|
||||
|
||||
def facebook_request(self, method, callback, **args):
|
||||
@@ -899,7 +924,7 @@ class FacebookMixin(object):
|
||||
args["sig"] = self._signature(args)
|
||||
url = "http://api.facebook.com/restserver.php?" + \
|
||||
urllib.urlencode(args)
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
http.fetch(url, callback=self.async_callback(
|
||||
self._parse_response, callback))
|
||||
|
||||
@@ -922,17 +947,17 @@ class FacebookMixin(object):
|
||||
|
||||
def _parse_response(self, callback, response):
|
||||
if response.error:
|
||||
logging.warning("HTTP error from Facebook: %s", response.error)
|
||||
gen_log.warning("HTTP error from Facebook: %s", response.error)
|
||||
callback(None)
|
||||
return
|
||||
try:
|
||||
json = escape.json_decode(response.body)
|
||||
except Exception:
|
||||
logging.warning("Invalid JSON from Facebook: %r", response.body)
|
||||
gen_log.warning("Invalid JSON from Facebook: %r", response.body)
|
||||
callback(None)
|
||||
return
|
||||
if isinstance(json, dict) and json.get("error_code"):
|
||||
logging.warning("Facebook error: %d: %r", json["error_code"],
|
||||
gen_log.warning("Facebook error: %d: %r", json["error_code"],
|
||||
json.get("error_msg"))
|
||||
callback(None)
|
||||
return
|
||||
@@ -945,6 +970,14 @@ class FacebookMixin(object):
|
||||
body = body.encode("utf-8")
|
||||
return hashlib.md5(body).hexdigest()
|
||||
|
||||
def get_auth_http_client(self):
|
||||
"""Returns the AsyncHTTPClient instance to be used for auth requests.
|
||||
|
||||
May be overridden by subclasses to use an http client other than
|
||||
the default.
|
||||
"""
|
||||
return httpclient.AsyncHTTPClient()
|
||||
|
||||
|
||||
class FacebookGraphMixin(OAuth2Mixin):
|
||||
"""Facebook authentication using the new Graph API and OAuth2."""
|
||||
@@ -979,7 +1012,7 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
self.finish()
|
||||
|
||||
"""
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
args = {
|
||||
"redirect_uri": redirect_uri,
|
||||
"code": code,
|
||||
@@ -999,7 +1032,7 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
def _on_access_token(self, redirect_uri, client_id, client_secret,
|
||||
callback, fields, response):
|
||||
if response.error:
|
||||
logging.warning('Facebook auth error: %s' % str(response))
|
||||
gen_log.warning('Facebook auth error: %s' % str(response))
|
||||
callback(None)
|
||||
return
|
||||
|
||||
@@ -1073,7 +1106,7 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
if all_args:
|
||||
url += "?" + urllib.urlencode(all_args)
|
||||
callback = self.async_callback(self._on_facebook_request, callback)
|
||||
http = httpclient.AsyncHTTPClient()
|
||||
http = self.get_auth_http_client()
|
||||
if post_args is not None:
|
||||
http.fetch(url, method="POST", body=urllib.urlencode(post_args),
|
||||
callback=callback)
|
||||
@@ -1082,12 +1115,20 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
|
||||
def _on_facebook_request(self, callback, response):
|
||||
if response.error:
|
||||
logging.warning("Error response %s fetching %s", response.error,
|
||||
gen_log.warning("Error response %s fetching %s", response.error,
|
||||
response.request.url)
|
||||
callback(None)
|
||||
return
|
||||
callback(escape.json_decode(response.body))
|
||||
|
||||
def get_auth_http_client(self):
|
||||
"""Returns the AsyncHTTPClient instance to be used for auth requests.
|
||||
|
||||
May be overridden by subclasses to use an http client other than
|
||||
the default.
|
||||
"""
|
||||
return httpclient.AsyncHTTPClient()
|
||||
|
||||
|
||||
def _oauth_signature(consumer_token, method, url, parameters={}, token=None):
|
||||
"""Calculates the HMAC-SHA1 OAuth signature for the given request.
|
||||
|
||||
Reference in New Issue
Block a user