Created
March 17, 2012 20:00
-
-
Save adam-stokes/2064807 to your computer and use it in GitHub Desktop.
Tornado Dropbox oauth mixin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DropboxMixin(tornado.auth.OAuthMixin): | |
""" Dropbox OAuth authentication. | |
""" | |
_OAUTH_REQUEST_TOKEN_URL = "https://api.dropbox.com/1/oauth/request_token" | |
_OAUTH_ACCESS_TOKEN_URL = "https://api.dropbox.com/1/oauth/access_token" | |
_OAUTH_AUTHORIZE_URL = "https://www.dropbox.com/1/oauth/authorize" | |
_OAUTH_VERSION = "1.0" | |
_OAUTH_NO_CALLBACKS = False | |
def authorize_redirect(self, callback_uri=None, extra_params=None, | |
http_client=None): | |
"""Redirects the user to obtain OAuth authorization for this service. | |
Twitter and FriendFeed both require that you register a Callback | |
URL with your application. You should call this method to log the | |
user in, and then call get_authenticated_user() in the handler | |
you registered as your Callback URL to complete the authorization | |
process. | |
This method sets a cookie called _oauth_request_token which is | |
subsequently used (and cleared) in get_authenticated_user for | |
security purposes. | |
""" | |
http_client = httpclient.AsyncHTTPClient() | |
http_client.fetch( | |
self._oauth_request_token_url(), self.async_callback( | |
self._on_request_token, self._OAUTH_AUTHORIZE_URL, callback_uri)) | |
def get_authenticated_user(self, callback, http_client=None): | |
"""Gets the OAuth authorized user and access token on callback. | |
This method should be called from the handler for your registered | |
OAuth Callback URL to complete the registration process. We call | |
callback with the authenticated user, which in addition to standard | |
attributes like 'name' includes the 'access_key' attribute, which | |
contains the OAuth access you can use to make authorized requests | |
to this service on behalf of the user. | |
""" | |
request_key = escape.utf8(self.get_argument("oauth_token")) | |
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") | |
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") | |
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.fetch(self._oauth_access_token_url(token), | |
self.async_callback(self._on_access_token, callback)) | |
def _on_access_token(self, callback, response): | |
if response.error: | |
logging.warning("Could not fetch access token") | |
callback(None) | |
return | |
access_token = _oauth_parse_response(response.body) | |
self._oauth_get_user(access_token, self.async_callback( | |
self._on_oauth_get_user, access_token, callback)) | |
def _on_oauth_get_user(self, access_token, callback, user): | |
if not user: | |
callback(None) | |
return | |
user["access_token"] = access_token | |
callback(user) | |
def dropbox_request(self, path, callback, access_token=None, | |
post_args=None, **args): | |
# Add the OAuth resource request signature if we have credentials | |
url = "https://api.dropbox.com/1" + path | |
if access_token: | |
all_args = {} | |
all_args.update(args) | |
all_args.update(post_args or {}) | |
method = "POST" if post_args is not None else "GET" | |
oauth = self._oauth_request_parameters( | |
url, access_token, all_args, method=method) | |
args.update(oauth) | |
if args: url += "?" + urllib.urlencode(args) | |
callback = self.async_callback(self._on_dropbox_request, callback) | |
http = httpclient.AsyncHTTPClient() | |
if post_args is not None: | |
http.fetch(url, method="POST", body=urllib.urlencode(post_args), | |
callback=callback) | |
else: | |
http.fetch(url, callback=callback) | |
def _on_dropbox_request(self, callback, response): | |
if response.error: | |
print("Error response %s fetching %s", response.error, | |
response.request.url) | |
callback(None) | |
return | |
callback(escape.json_decode(response.body)) | |
def _oauth_consumer_token(self): | |
self.require_setting("dropbox_consumer_key", "Dropbox OAuth") | |
self.require_setting("dropbox_consumer_secret", "Dropbox OAuth") | |
return dict( | |
key=self.settings["dropbox_consumer_key"], | |
secret=self.settings["dropbox_consumer_secret"]) | |
def _oauth_get_user(self, access_token, callback): | |
callback = self.async_callback(self._parse_user_response, callback) | |
self.dropbox_request( | |
"/account/info", | |
access_token=access_token, | |
callback=callback) | |
def _parse_user_response(self, callback, user): | |
if user: | |
user["username"] = user["display_name"] | |
callback(user) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment