| Index: appengine/chromium_build_logs/third_party/apiclient/oauth.py
|
| diff --git a/appengine/chromium_build_logs/third_party/apiclient/oauth.py b/appengine/chromium_build_logs/third_party/apiclient/oauth.py
|
| deleted file mode 100644
|
| index 136adcdc1b256a4a43434a0a5fb488d4795b4cb1..0000000000000000000000000000000000000000
|
| --- a/appengine/chromium_build_logs/third_party/apiclient/oauth.py
|
| +++ /dev/null
|
| @@ -1,443 +0,0 @@
|
| -# Copyright (C) 2010 Google Inc.
|
| -#
|
| -# Licensed under the Apache License, Version 2.0 (the "License");
|
| -# you may not use this file except in compliance with the License.
|
| -# You may obtain a copy of the License at
|
| -#
|
| -# http://www.apache.org/licenses/LICENSE-2.0
|
| -#
|
| -# Unless required by applicable law or agreed to in writing, software
|
| -# distributed under the License is distributed on an "AS IS" BASIS,
|
| -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -# See the License for the specific language governing permissions and
|
| -# limitations under the License.
|
| -
|
| -"""Utilities for OAuth.
|
| -
|
| -Utilities for making it easier to work with OAuth.
|
| -"""
|
| -
|
| -__author__ = 'jcgregorio@google.com (Joe Gregorio)'
|
| -
|
| -
|
| -import copy
|
| -import httplib2
|
| -import logging
|
| -import oauth2 as oauth
|
| -import urllib
|
| -import urlparse
|
| -
|
| -from oauth2client.anyjson import simplejson
|
| -from oauth2client.client import Credentials
|
| -from oauth2client.client import Flow
|
| -from oauth2client.client import Storage
|
| -
|
| -try:
|
| - from urlparse import parse_qsl
|
| -except ImportError:
|
| - from cgi import parse_qsl
|
| -
|
| -
|
| -class Error(Exception):
|
| - """Base error for this module."""
|
| - pass
|
| -
|
| -
|
| -class RequestError(Error):
|
| - """Error occurred during request."""
|
| - pass
|
| -
|
| -
|
| -class MissingParameter(Error):
|
| - pass
|
| -
|
| -
|
| -class CredentialsInvalidError(Error):
|
| - pass
|
| -
|
| -
|
| -def _abstract():
|
| - raise NotImplementedError('You need to override this function')
|
| -
|
| -
|
| -def _oauth_uri(name, discovery, params):
|
| - """Look up the OAuth URI from the discovery
|
| - document and add query parameters based on
|
| - params.
|
| -
|
| - name - The name of the OAuth URI to lookup, one
|
| - of 'request', 'access', or 'authorize'.
|
| - discovery - Portion of discovery document the describes
|
| - the OAuth endpoints.
|
| - params - Dictionary that is used to form the query parameters
|
| - for the specified URI.
|
| - """
|
| - if name not in ['request', 'access', 'authorize']:
|
| - raise KeyError(name)
|
| - keys = discovery[name]['parameters'].keys()
|
| - query = {}
|
| - for key in keys:
|
| - if key in params:
|
| - query[key] = params[key]
|
| - return discovery[name]['url'] + '?' + urllib.urlencode(query)
|
| -
|
| -
|
| -
|
| -class OAuthCredentials(Credentials):
|
| - """Credentials object for OAuth 1.0a
|
| - """
|
| -
|
| - def __init__(self, consumer, token, user_agent):
|
| - """
|
| - consumer - An instance of oauth.Consumer.
|
| - token - An instance of oauth.Token constructed with
|
| - the access token and secret.
|
| - user_agent - The HTTP User-Agent to provide for this application.
|
| - """
|
| - self.consumer = consumer
|
| - self.token = token
|
| - self.user_agent = user_agent
|
| - self.store = None
|
| -
|
| - # True if the credentials have been revoked
|
| - self._invalid = False
|
| -
|
| - @property
|
| - def invalid(self):
|
| - """True if the credentials are invalid, such as being revoked."""
|
| - return getattr(self, "_invalid", False)
|
| -
|
| - def set_store(self, store):
|
| - """Set the storage for the credential.
|
| -
|
| - Args:
|
| - store: callable, a callable that when passed a Credential
|
| - will store the credential back to where it came from.
|
| - This is needed to store the latest access_token if it
|
| - has been revoked.
|
| - """
|
| - self.store = store
|
| -
|
| - def __getstate__(self):
|
| - """Trim the state down to something that can be pickled."""
|
| - d = copy.copy(self.__dict__)
|
| - del d['store']
|
| - return d
|
| -
|
| - def __setstate__(self, state):
|
| - """Reconstitute the state of the object from being pickled."""
|
| - self.__dict__.update(state)
|
| - self.store = None
|
| -
|
| - def authorize(self, http):
|
| - """Authorize an httplib2.Http instance with these Credentials
|
| -
|
| - Args:
|
| - http - An instance of httplib2.Http
|
| - or something that acts like it.
|
| -
|
| - Returns:
|
| - A modified instance of http that was passed in.
|
| -
|
| - Example:
|
| -
|
| - h = httplib2.Http()
|
| - h = credentials.authorize(h)
|
| -
|
| - You can't create a new OAuth
|
| - subclass of httplib2.Authenication because
|
| - it never gets passed the absolute URI, which is
|
| - needed for signing. So instead we have to overload
|
| - 'request' with a closure that adds in the
|
| - Authorization header and then calls the original version
|
| - of 'request()'.
|
| - """
|
| - request_orig = http.request
|
| - signer = oauth.SignatureMethod_HMAC_SHA1()
|
| -
|
| - # The closure that will replace 'httplib2.Http.request'.
|
| - def new_request(uri, method='GET', body=None, headers=None,
|
| - redirections=httplib2.DEFAULT_MAX_REDIRECTS,
|
| - connection_type=None):
|
| - """Modify the request headers to add the appropriate
|
| - Authorization header."""
|
| - response_code = 302
|
| - http.follow_redirects = False
|
| - while response_code in [301, 302]:
|
| - req = oauth.Request.from_consumer_and_token(
|
| - self.consumer, self.token, http_method=method, http_url=uri)
|
| - req.sign_request(signer, self.consumer, self.token)
|
| - if headers is None:
|
| - headers = {}
|
| - headers.update(req.to_header())
|
| - if 'user-agent' in headers:
|
| - headers['user-agent'] = self.user_agent + ' ' + headers['user-agent']
|
| - else:
|
| - headers['user-agent'] = self.user_agent
|
| -
|
| - resp, content = request_orig(uri, method, body, headers,
|
| - redirections, connection_type)
|
| - response_code = resp.status
|
| - if response_code in [301, 302]:
|
| - uri = resp['location']
|
| -
|
| - # Update the stored credential if it becomes invalid.
|
| - if response_code == 401:
|
| - logging.info('Access token no longer valid: %s' % content)
|
| - self._invalid = True
|
| - if self.store is not None:
|
| - self.store(self)
|
| - raise CredentialsInvalidError("Credentials are no longer valid.")
|
| -
|
| - return resp, content
|
| -
|
| - http.request = new_request
|
| - return http
|
| -
|
| -
|
| -class TwoLeggedOAuthCredentials(Credentials):
|
| - """Two Legged Credentials object for OAuth 1.0a.
|
| -
|
| - The Two Legged object is created directly, not from a flow. Once you
|
| - authorize and httplib2.Http instance you can change the requestor and that
|
| - change will propogate to the authorized httplib2.Http instance. For example:
|
| -
|
| - http = httplib2.Http()
|
| - http = credentials.authorize(http)
|
| -
|
| - credentials.requestor = 'foo@example.info'
|
| - http.request(...)
|
| - credentials.requestor = 'bar@example.info'
|
| - http.request(...)
|
| - """
|
| -
|
| - def __init__(self, consumer_key, consumer_secret, user_agent):
|
| - """
|
| - Args:
|
| - consumer_key: string, An OAuth 1.0 consumer key
|
| - consumer_secret: string, An OAuth 1.0 consumer secret
|
| - user_agent: string, The HTTP User-Agent to provide for this application.
|
| - """
|
| - self.consumer = oauth.Consumer(consumer_key, consumer_secret)
|
| - self.user_agent = user_agent
|
| - self.store = None
|
| -
|
| - # email address of the user to act on the behalf of.
|
| - self._requestor = None
|
| -
|
| - @property
|
| - def invalid(self):
|
| - """True if the credentials are invalid, such as being revoked.
|
| -
|
| - Always returns False for Two Legged Credentials.
|
| - """
|
| - return False
|
| -
|
| - def getrequestor(self):
|
| - return self._requestor
|
| -
|
| - def setrequestor(self, email):
|
| - self._requestor = email
|
| -
|
| - requestor = property(getrequestor, setrequestor, None,
|
| - 'The email address of the user to act on behalf of')
|
| -
|
| - def set_store(self, store):
|
| - """Set the storage for the credential.
|
| -
|
| - Args:
|
| - store: callable, a callable that when passed a Credential
|
| - will store the credential back to where it came from.
|
| - This is needed to store the latest access_token if it
|
| - has been revoked.
|
| - """
|
| - self.store = store
|
| -
|
| - def __getstate__(self):
|
| - """Trim the state down to something that can be pickled."""
|
| - d = copy.copy(self.__dict__)
|
| - del d['store']
|
| - return d
|
| -
|
| - def __setstate__(self, state):
|
| - """Reconstitute the state of the object from being pickled."""
|
| - self.__dict__.update(state)
|
| - self.store = None
|
| -
|
| - def authorize(self, http):
|
| - """Authorize an httplib2.Http instance with these Credentials
|
| -
|
| - Args:
|
| - http - An instance of httplib2.Http
|
| - or something that acts like it.
|
| -
|
| - Returns:
|
| - A modified instance of http that was passed in.
|
| -
|
| - Example:
|
| -
|
| - h = httplib2.Http()
|
| - h = credentials.authorize(h)
|
| -
|
| - You can't create a new OAuth
|
| - subclass of httplib2.Authenication because
|
| - it never gets passed the absolute URI, which is
|
| - needed for signing. So instead we have to overload
|
| - 'request' with a closure that adds in the
|
| - Authorization header and then calls the original version
|
| - of 'request()'.
|
| - """
|
| - request_orig = http.request
|
| - signer = oauth.SignatureMethod_HMAC_SHA1()
|
| -
|
| - # The closure that will replace 'httplib2.Http.request'.
|
| - def new_request(uri, method='GET', body=None, headers=None,
|
| - redirections=httplib2.DEFAULT_MAX_REDIRECTS,
|
| - connection_type=None):
|
| - """Modify the request headers to add the appropriate
|
| - Authorization header."""
|
| - response_code = 302
|
| - http.follow_redirects = False
|
| - while response_code in [301, 302]:
|
| - # add in xoauth_requestor_id=self._requestor to the uri
|
| - if self._requestor is None:
|
| - raise MissingParameter(
|
| - 'Requestor must be set before using TwoLeggedOAuthCredentials')
|
| - parsed = list(urlparse.urlparse(uri))
|
| - q = parse_qsl(parsed[4])
|
| - q.append(('xoauth_requestor_id', self._requestor))
|
| - parsed[4] = urllib.urlencode(q)
|
| - uri = urlparse.urlunparse(parsed)
|
| -
|
| - req = oauth.Request.from_consumer_and_token(
|
| - self.consumer, None, http_method=method, http_url=uri)
|
| - req.sign_request(signer, self.consumer, None)
|
| - if headers is None:
|
| - headers = {}
|
| - headers.update(req.to_header())
|
| - if 'user-agent' in headers:
|
| - headers['user-agent'] = self.user_agent + ' ' + headers['user-agent']
|
| - else:
|
| - headers['user-agent'] = self.user_agent
|
| - resp, content = request_orig(uri, method, body, headers,
|
| - redirections, connection_type)
|
| - response_code = resp.status
|
| - if response_code in [301, 302]:
|
| - uri = resp['location']
|
| -
|
| - if response_code == 401:
|
| - logging.info('Access token no longer valid: %s' % content)
|
| - # Do not store the invalid state of the Credentials because
|
| - # being 2LO they could be reinstated in the future.
|
| - raise CredentialsInvalidError("Credentials are invalid.")
|
| -
|
| - return resp, content
|
| -
|
| - http.request = new_request
|
| - return http
|
| -
|
| -
|
| -class FlowThreeLegged(Flow):
|
| - """Does the Three Legged Dance for OAuth 1.0a.
|
| - """
|
| -
|
| - def __init__(self, discovery, consumer_key, consumer_secret, user_agent,
|
| - **kwargs):
|
| - """
|
| - discovery - Section of the API discovery document that describes
|
| - the OAuth endpoints.
|
| - consumer_key - OAuth consumer key
|
| - consumer_secret - OAuth consumer secret
|
| - user_agent - The HTTP User-Agent that identifies the application.
|
| - **kwargs - The keyword arguments are all optional and required
|
| - parameters for the OAuth calls.
|
| - """
|
| - self.discovery = discovery
|
| - self.consumer_key = consumer_key
|
| - self.consumer_secret = consumer_secret
|
| - self.user_agent = user_agent
|
| - self.params = kwargs
|
| - self.request_token = {}
|
| - required = {}
|
| - for uriinfo in discovery.itervalues():
|
| - for name, value in uriinfo['parameters'].iteritems():
|
| - if value['required'] and not name.startswith('oauth_'):
|
| - required[name] = 1
|
| - for key in required.iterkeys():
|
| - if key not in self.params:
|
| - raise MissingParameter('Required parameter %s not supplied' % key)
|
| -
|
| - def step1_get_authorize_url(self, oauth_callback='oob'):
|
| - """Returns a URI to redirect to the provider.
|
| -
|
| - oauth_callback - Either the string 'oob' for a non-web-based application,
|
| - or a URI that handles the callback from the authorization
|
| - server.
|
| -
|
| - If oauth_callback is 'oob' then pass in the
|
| - generated verification code to step2_exchange,
|
| - otherwise pass in the query parameters received
|
| - at the callback uri to step2_exchange.
|
| - """
|
| - consumer = oauth.Consumer(self.consumer_key, self.consumer_secret)
|
| - client = oauth.Client(consumer)
|
| -
|
| - headers = {
|
| - 'user-agent': self.user_agent,
|
| - 'content-type': 'application/x-www-form-urlencoded'
|
| - }
|
| - body = urllib.urlencode({'oauth_callback': oauth_callback})
|
| - uri = _oauth_uri('request', self.discovery, self.params)
|
| -
|
| - resp, content = client.request(uri, 'POST', headers=headers,
|
| - body=body)
|
| - if resp['status'] != '200':
|
| - logging.error('Failed to retrieve temporary authorization: %s', content)
|
| - raise RequestError('Invalid response %s.' % resp['status'])
|
| -
|
| - self.request_token = dict(parse_qsl(content))
|
| -
|
| - auth_params = copy.copy(self.params)
|
| - auth_params['oauth_token'] = self.request_token['oauth_token']
|
| -
|
| - return _oauth_uri('authorize', self.discovery, auth_params)
|
| -
|
| - def step2_exchange(self, verifier):
|
| - """Exhanges an authorized request token
|
| - for OAuthCredentials.
|
| -
|
| - Args:
|
| - verifier: string, dict - either the verifier token, or a dictionary
|
| - of the query parameters to the callback, which contains
|
| - the oauth_verifier.
|
| - Returns:
|
| - The Credentials object.
|
| - """
|
| -
|
| - if not (isinstance(verifier, str) or isinstance(verifier, unicode)):
|
| - verifier = verifier['oauth_verifier']
|
| -
|
| - token = oauth.Token(
|
| - self.request_token['oauth_token'],
|
| - self.request_token['oauth_token_secret'])
|
| - token.set_verifier(verifier)
|
| - consumer = oauth.Consumer(self.consumer_key, self.consumer_secret)
|
| - client = oauth.Client(consumer, token)
|
| -
|
| - headers = {
|
| - 'user-agent': self.user_agent,
|
| - 'content-type': 'application/x-www-form-urlencoded'
|
| - }
|
| -
|
| - uri = _oauth_uri('access', self.discovery, self.params)
|
| - resp, content = client.request(uri, 'POST', headers=headers)
|
| - if resp['status'] != '200':
|
| - logging.error('Failed to retrieve access token: %s', content)
|
| - raise RequestError('Invalid response %s.' % resp['status'])
|
| -
|
| - oauth_params = dict(parse_qsl(content))
|
| - token = oauth.Token(
|
| - oauth_params['oauth_token'],
|
| - oauth_params['oauth_token_secret'])
|
| -
|
| - return OAuthCredentials(consumer, token, self.user_agent)
|
|
|