Making oauth2client/ files pass PEP8.

This commit is contained in:
Danny Hermes
2015-08-20 16:08:20 -07:00
parent b70baa4fab
commit d7c0c38b8d
20 changed files with 558 additions and 495 deletions

View File

@@ -58,8 +58,8 @@ class PyCryptoVerifier(object):
Args: Args:
key_pem: string, public key in PEM format. key_pem: string, public key in PEM format.
is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it
expected to be an RSA key in PEM format. is expected to be an RSA key in PEM format.
Returns: Returns:
Verifier instance. Verifier instance.
@@ -123,6 +123,7 @@ class PyCryptoSigner(object):
raise NotImplementedError( raise NotImplementedError(
'PKCS12 format is not supported by the PyCrypto library. ' 'PKCS12 format is not supported by the PyCrypto library. '
'Try converting to a "PEM" ' 'Try converting to a "PEM" '
'(openssl pkcs12 -in xxxxx.p12 -nodes -nocerts > privatekey.pem) ' '(openssl pkcs12 -in xxxxx.p12 -nodes -nocerts > '
'privatekey.pem) '
'or using PyOpenSSL if native code is an option.') 'or using PyOpenSSL if native code is an option.')
return PyCryptoSigner(pkey) return PyCryptoSigner(pkey)

View File

@@ -132,7 +132,8 @@ def xsrf_secret_key():
model.secret = _generate_new_xsrf_secret_key() model.secret = _generate_new_xsrf_secret_key()
model.put() model.put()
secret = model.secret secret = model.secret
memcache.add(XSRF_MEMCACHE_ID, secret, namespace=OAUTH2CLIENT_NAMESPACE) memcache.add(XSRF_MEMCACHE_ID, secret,
namespace=OAUTH2CLIENT_NAMESPACE)
return str(secret) return str(secret)
@@ -166,7 +167,8 @@ class AppAssertionCredentials(AssertionCredentials):
self._kwargs = kwargs self._kwargs = kwargs
self.service_account_id = kwargs.get('service_account_id', None) self.service_account_id = kwargs.get('service_account_id', None)
# Assertion type is no longer used, but still in the parent class signature. # Assertion type is no longer used, but still in the
# parent class signature.
super(AppAssertionCredentials, self).__init__(None) super(AppAssertionCredentials, self).__init__(None)
@classmethod @classmethod
@@ -199,7 +201,8 @@ class AppAssertionCredentials(AssertionCredentials):
@property @property
def serialization_data(self): def serialization_data(self):
raise NotImplementedError('Cannot serialize credentials for AppEngine.') raise NotImplementedError('Cannot serialize credentials '
'for Google App Engine.')
def create_scoped_required(self): def create_scoped_required(self):
return not self.scope return not self.scope
@@ -220,8 +223,8 @@ class FlowProperty(db.Property):
# For writing to datastore. # For writing to datastore.
def get_value_for_datastore(self, model_instance): def get_value_for_datastore(self, model_instance):
flow = super(FlowProperty, flow = super(FlowProperty, self).get_value_for_datastore(
self).get_value_for_datastore(model_instance) model_instance)
return db.Blob(pickle.dumps(flow)) return db.Blob(pickle.dumps(flow))
# For reading from datastore. # For reading from datastore.
@@ -266,7 +269,8 @@ if ndb is not None:
logger.info('validate: Got type %s', type(value)) logger.info('validate: Got type %s', type(value))
if value is not None and not isinstance(value, Flow): if value is not None and not isinstance(value, Flow):
raise TypeError('Property %s must be convertible to a flow ' raise TypeError('Property %s must be convertible to a flow '
'instance; received: %s.' % (self._name, value)) 'instance; received: %s.' % (self._name,
value))
class CredentialsProperty(db.Property): class CredentialsProperty(db.Property):
@@ -282,8 +286,8 @@ class CredentialsProperty(db.Property):
# For writing to datastore. # For writing to datastore.
def get_value_for_datastore(self, model_instance): def get_value_for_datastore(self, model_instance):
logger.info("get: Got type " + str(type(model_instance))) logger.info("get: Got type " + str(type(model_instance)))
cred = super(CredentialsProperty, cred = super(CredentialsProperty, self).get_value_for_datastore(
self).get_value_for_datastore(model_instance) model_instance)
if cred is None: if cred is None:
cred = '' cred = ''
else: else:
@@ -310,14 +314,10 @@ class CredentialsProperty(db.Property):
raise db.BadValueError('Property %s must be convertible ' raise db.BadValueError('Property %s must be convertible '
'to a Credentials instance (%s)' % 'to a Credentials instance (%s)' %
(self.name, value)) (self.name, value))
#if value is not None and not isinstance(value, Credentials):
# return None
return value return value
if ndb is not None: if ndb is not None:
# TODO(dhermes): Turn this into a JsonProperty and overhaul the Credentials # TODO(dhermes): Turn this into a JsonProperty and overhaul the Credentials
# and subclass mechanics to use new_from_dict, to_dict, # and subclass mechanics to use new_from_dict, to_dict,
# from_dict, etc. # from_dict, etc.
@@ -344,8 +344,9 @@ if ndb is not None:
""" """
logger.info('validate: Got type %s', type(value)) logger.info('validate: Got type %s', type(value))
if value is not None and not isinstance(value, Credentials): if value is not None and not isinstance(value, Credentials):
raise TypeError('Property %s must be convertible to a credentials ' raise TypeError('Property %s must be convertible to a '
'instance; received: %s.' % (self._name, value)) 'credentials instance; received: %s.' %
(self._name, value))
def _to_base_type(self, value): def _to_base_type(self, value):
"""Converts our validated value to a JSON serialized string. """Converts our validated value to a JSON serialized string.
@@ -409,7 +410,8 @@ class StorageByKeyName(Storage):
""" """
if key_name is None: if key_name is None:
if user is None: if user is None:
raise ValueError('StorageByKeyName called with no key name or user.') raise ValueError('StorageByKeyName called with no '
'key name or user.')
key_name = user.user_id() key_name = user.user_id()
self._model = model self._model = model
@@ -423,15 +425,17 @@ class StorageByKeyName(Storage):
Returns: Returns:
Boolean indicating whether or not the model is an NDB or DB model. Boolean indicating whether or not the model is an NDB or DB model.
""" """
# issubclass will fail if one of the arguments is not a class, only need # issubclass will fail if one of the arguments is not a class, only
# worry about new-style classes since ndb and db models are new-style # need worry about new-style classes since ndb and db models are
# new-style
if isinstance(self._model, type): if isinstance(self._model, type):
if ndb is not None and issubclass(self._model, ndb.Model): if ndb is not None and issubclass(self._model, ndb.Model):
return True return True
elif issubclass(self._model, db.Model): elif issubclass(self._model, db.Model):
return False return False
raise TypeError('Model class not an NDB or DB model: %s.' % (self._model, )) raise TypeError('Model class not an NDB or DB model: %s.' %
(self._model,))
def _get_entity(self): def _get_entity(self):
"""Retrieve entity from datastore. """Retrieve entity from datastore.
@@ -640,7 +644,6 @@ class OAuth2Decorator(object):
_credentials_class=CredentialsModel, _credentials_class=CredentialsModel,
_credentials_property_name='credentials', _credentials_property_name='credentials',
**kwargs): **kwargs):
"""Constructor for OAuth2Decorator """Constructor for OAuth2Decorator
Args: Args:
@@ -659,13 +662,14 @@ class OAuth2Decorator(object):
provider can be used. provider can be used.
user_agent: string, User agent of your application, default to user_agent: string, User agent of your application, default to
None. None.
message: Message to display if there are problems with the OAuth 2.0 message: Message to display if there are problems with the
configuration. The message may contain HTML and will be OAuth 2.0 configuration. The message may contain HTML and
presented on the web interface for any method that uses will be presented on the web interface for any method that
the decorator. uses the decorator.
callback_path: string, The absolute path to use as the callback callback_path: string, The absolute path to use as the callback
URI. Note that this must match up with the URI given URI. Note that this must match up with the URI given
when registering the application in the APIs Console. when registering the application in the APIs
Console.
token_response_param: string. If provided, the full JSON response token_response_param: string. If provided, the full JSON response
to the access token request will be encoded to the access token request will be encoded
and included in this query parameter in the and included in this query parameter in the
@@ -730,7 +734,8 @@ class OAuth2Decorator(object):
return return
user = users.get_current_user() user = users.get_current_user()
# Don't use @login_decorator as this could be used in a POST request. # Don't use @login_decorator as this could be used in a
# POST request.
if not user: if not user:
request_handler.redirect(users.create_login_url( request_handler.redirect(users.create_login_url(
request_handler.request.uri)) request_handler.request.uri))
@@ -739,7 +744,8 @@ class OAuth2Decorator(object):
self._create_flow(request_handler) self._create_flow(request_handler)
# Store the request URI in 'state' so we can use it later # Store the request URI in 'state' so we can use it later
self.flow.params['state'] = _build_state_value(request_handler, user) self.flow.params['state'] = _build_state_value(
request_handler, user)
self.credentials = self._storage_class( self.credentials = self._storage_class(
self._credentials_class, None, self._credentials_class, None,
self._credentials_property_name, user=user).get() self._credentials_property_name, user=user).get()
@@ -769,13 +775,11 @@ class OAuth2Decorator(object):
if self.flow is None: if self.flow is None:
redirect_uri = request_handler.request.relative_url( redirect_uri = request_handler.request.relative_url(
self._callback_path) # Usually /oauth2callback self._callback_path) # Usually /oauth2callback
self.flow = OAuth2WebServerFlow(self._client_id, self._client_secret, self.flow = OAuth2WebServerFlow(
self._scope, redirect_uri=redirect_uri, self._client_id, self._client_secret, self._scope,
user_agent=self._user_agent, redirect_uri=redirect_uri, user_agent=self._user_agent,
auth_uri=self._auth_uri, auth_uri=self._auth_uri, token_uri=self._token_uri,
token_uri=self._token_uri, revoke_uri=self._revoke_uri, **self._kwargs)
revoke_uri=self._revoke_uri,
**self._kwargs)
def oauth_aware(self, method): def oauth_aware(self, method):
"""Decorator that sets up for OAuth 2.0 dance, but doesn't do it. """Decorator that sets up for OAuth 2.0 dance, but doesn't do it.
@@ -797,7 +801,8 @@ class OAuth2Decorator(object):
return return
user = users.get_current_user() user = users.get_current_user()
# Don't use @login_decorator as this could be used in a POST request. # Don't use @login_decorator as this could be used in a
# POST request.
if not user: if not user:
request_handler.redirect(users.create_login_url( request_handler.redirect(users.create_login_url(
request_handler.request.uri)) request_handler.request.uri))
@@ -805,7 +810,8 @@ class OAuth2Decorator(object):
self._create_flow(request_handler) self._create_flow(request_handler)
self.flow.params['state'] = _build_state_value(request_handler, user) self.flow.params['state'] = _build_state_value(request_handler,
user)
self.credentials = self._storage_class( self.credentials = self._storage_class(
self._credentials_class, None, self._credentials_class, None,
self._credentials_property_name, user=user).get() self._credentials_property_name, user=user).get()
@@ -885,21 +891,26 @@ class OAuth2Decorator(object):
if error: if error:
errormsg = self.request.get('error_description', error) errormsg = self.request.get('error_description', error)
self.response.out.write( self.response.out.write(
'The authorization request failed: %s' % _safe_html(errormsg)) 'The authorization request failed: %s' %
_safe_html(errormsg))
else: else:
user = users.get_current_user() user = users.get_current_user()
decorator._create_flow(self) decorator._create_flow(self)
credentials = decorator.flow.step2_exchange(self.request.params) credentials = decorator.flow.step2_exchange(
self.request.params)
decorator._storage_class( decorator._storage_class(
decorator._credentials_class, None, decorator._credentials_class, None,
decorator._credentials_property_name, user=user).put(credentials) decorator._credentials_property_name,
redirect_uri = _parse_state_value(str(self.request.get('state')), user=user).put(credentials)
user) redirect_uri = _parse_state_value(
str(self.request.get('state')), user)
if decorator._token_response_param and credentials.token_response: if (decorator._token_response_param and
credentials.token_response):
resp_json = json.dumps(credentials.token_response) resp_json = json.dumps(credentials.token_response)
redirect_uri = util._add_query_parameter( redirect_uri = util._add_query_parameter(
redirect_uri, decorator._token_response_param, resp_json) redirect_uri, decorator._token_response_param,
resp_json)
self.redirect(redirect_uri) self.redirect(redirect_uri)
@@ -959,11 +970,13 @@ class OAuth2DecoratorFromClientSecrets(OAuth2Decorator):
**kwargs: dict, Keyword arguments are passed along as kwargs to **kwargs: dict, Keyword arguments are passed along as kwargs to
the OAuth2WebServerFlow constructor. the OAuth2WebServerFlow constructor.
""" """
client_type, client_info = clientsecrets.loadfile(filename, cache=cache) client_type, client_info = clientsecrets.loadfile(filename,
if client_type not in [ cache=cache)
clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED]: if client_type not in (clientsecrets.TYPE_WEB,
clientsecrets.TYPE_INSTALLED):
raise InvalidClientSecretsError( raise InvalidClientSecretsError(
"OAuth2Decorator doesn't support this OAuth 2.0 flow.") "OAuth2Decorator doesn't support this OAuth 2.0 flow.")
constructor_kwargs = dict(kwargs) constructor_kwargs = dict(kwargs)
constructor_kwargs.update({ constructor_kwargs.update({
'auth_uri': client_info['auth_uri'], 'auth_uri': client_info['auth_uri'],

View File

@@ -93,12 +93,13 @@ _CLOUDSDK_CONFIG_ENV_VAR = 'CLOUDSDK_CONFIG'
# The error message we show users when we can't find the Application # The error message we show users when we can't find the Application
# Default Credentials. # Default Credentials.
ADC_HELP_MSG = ( ADC_HELP_MSG = (
'The Application Default Credentials are not available. They are available ' 'The Application Default Credentials are not available. They are '
'if running in Google Compute Engine. Otherwise, the environment variable ' 'available if running in Google Compute Engine. Otherwise, the '
+ GOOGLE_APPLICATION_CREDENTIALS + 'environment variable ' +
GOOGLE_APPLICATION_CREDENTIALS +
' must be defined pointing to a file defining the credentials. See ' ' must be defined pointing to a file defining the credentials. See '
'https://developers.google.com/accounts/docs/application-default-credentials' # pylint:disable=line-too-long 'https://developers.google.com/accounts/docs/'
' for more information.') 'application-default-credentials for more information.')
# The access token along with the seconds in which it expires. # The access token along with the seconds in which it expires.
AccessTokenInfo = collections.namedtuple( AccessTokenInfo = collections.namedtuple(
@@ -283,16 +284,19 @@ class Credentials(object):
""" """
json_string_as_unicode = _from_bytes(s) json_string_as_unicode = _from_bytes(s)
data = json.loads(json_string_as_unicode) data = json.loads(json_string_as_unicode)
# Find and call the right classmethod from_json() to restore the object. # Find and call the right classmethod from_json() to restore
# the object.
module_name = data['_module'] module_name = data['_module']
try: try:
module_obj = __import__(module_name) module_obj = __import__(module_name)
except ImportError: except ImportError:
# In case there's an object from the old package structure, update it # In case there's an object from the old package structure,
# update it
module_name = module_name.replace('.googleapiclient', '') module_name = module_name.replace('.googleapiclient', '')
module_obj = __import__(module_name) module_obj = __import__(module_name)
module_obj = __import__(module_name, fromlist=module_name.split('.')[:-1]) module_obj = __import__(module_name,
fromlist=module_name.split('.')[:-1])
kls = getattr(module_obj, data['_class']) kls = getattr(module_obj, data['_class'])
from_json = getattr(kls, 'from_json') from_json = getattr(kls, 'from_json')
return from_json(json_string_as_unicode) return from_json(json_string_as_unicode)
@@ -522,10 +526,9 @@ class OAuth2Credentials(Credentials):
The modified http.request method will add authentication headers to The modified http.request method will add authentication headers to
each request and will refresh access_tokens when a 401 is received on a each request and will refresh access_tokens when a 401 is received on a
request. In addition the http.request method has a credentials property, request. In addition the http.request method has a credentials
http.request.credentials, which is the Credentials object that property, http.request.credentials, which is the Credentials object
authorized it. that authorized it.
Args: Args:
http: An instance of ``httplib2.Http`` or something that acts http: An instance of ``httplib2.Http`` or something that acts
@@ -552,7 +555,8 @@ class OAuth2Credentials(Credentials):
redirections=httplib2.DEFAULT_MAX_REDIRECTS, redirections=httplib2.DEFAULT_MAX_REDIRECTS,
connection_type=None): connection_type=None):
if not self.access_token: if not self.access_token:
logger.info('Attempting refresh to obtain initial access_token') logger.info('Attempting refresh to obtain '
'initial access_token')
self._refresh(request_orig) self._refresh(request_orig)
# Clone and modify the request headers to add the appropriate # Clone and modify the request headers to add the appropriate
@@ -565,7 +569,8 @@ class OAuth2Credentials(Credentials):
if self.user_agent is not None: if self.user_agent is not None:
if 'user-agent' in headers: if 'user-agent' in headers:
headers['user-agent'] = self.user_agent + ' ' + headers['user-agent'] headers['user-agent'] = (self.user_agent + ' ' +
headers['user-agent'])
else: else:
headers['user-agent'] = self.user_agent headers['user-agent'] = self.user_agent
@@ -574,23 +579,26 @@ class OAuth2Credentials(Credentials):
('read', 'seek', 'tell')): ('read', 'seek', 'tell')):
body_stream_position = body.tell() body_stream_position = body.tell()
resp, content = request_orig(uri, method, body, clean_headers(headers), resp, content = request_orig(uri, method, body,
clean_headers(headers),
redirections, connection_type) redirections, connection_type)
# A stored token may expire between the time it is retrieved and the time # A stored token may expire between the time it is retrieved and
# the request is made, so we may need to try twice. # the time the request is made, so we may need to try twice.
max_refresh_attempts = 2 max_refresh_attempts = 2
for refresh_attempt in range(max_refresh_attempts): for refresh_attempt in range(max_refresh_attempts):
if resp.status not in REFRESH_STATUS_CODES: if resp.status not in REFRESH_STATUS_CODES:
break break
logger.info('Refreshing due to a %s (attempt %s/%s)', resp.status, logger.info('Refreshing due to a %s (attempt %s/%s)',
refresh_attempt + 1, max_refresh_attempts) resp.status, refresh_attempt + 1,
max_refresh_attempts)
self._refresh(request_orig) self._refresh(request_orig)
self.apply(headers) self.apply(headers)
if body_stream_position is not None: if body_stream_position is not None:
body.seek(body_stream_position) body.seek(body_stream_position)
resp, content = request_orig(uri, method, body, clean_headers(headers), resp, content = request_orig(uri, method, body,
clean_headers(headers),
redirections, connection_type) redirections, connection_type)
return (resp, content) return (resp, content)
@@ -869,8 +877,8 @@ class OAuth2Credentials(Credentials):
if self.store: if self.store:
self.store.locked_put(self) self.store.locked_put(self)
else: else:
# An {'error':...} response body means the token is expired or revoked, # An {'error':...} response body means the token is expired or
# so we flag the credentials as such. # revoked, so we flag the credentials as such.
logger.info('Failed to retrieve access token: %s', content) logger.info('Failed to retrieve access token: %s', content)
error_msg = 'Invalid response %s.' % resp['status'] error_msg = 'Invalid response %s.' % resp['status']
try: try:
@@ -955,7 +963,8 @@ class OAuth2Credentials(Credentials):
""" """
logger.info('Refreshing scopes') logger.info('Refreshing scopes')
query_params = {'access_token': token, 'fields': 'scope'} query_params = {'access_token': token, 'fields': 'scope'}
token_info_uri = _update_query_params(self.token_info_uri, query_params) token_info_uri = _update_query_params(self.token_info_uri,
query_params)
resp, content = http_request(token_info_uri) resp, content = http_request(token_info_uri)
content = _from_bytes(content) content = _from_bytes(content)
if resp.status == 200: if resp.status == 200:
@@ -1166,8 +1175,8 @@ class GoogleCredentials(OAuth2Credentials):
is None. is None.
""" """
super(GoogleCredentials, self).__init__( super(GoogleCredentials, self).__init__(
access_token, client_id, client_secret, refresh_token, token_expiry, access_token, client_id, client_secret, refresh_token,
token_uri, user_agent, revoke_uri=revoke_uri) token_expiry, token_uri, user_agent, revoke_uri=revoke_uri)
def create_scoped_required(self): def create_scoped_required(self):
"""Whether this Credentials object is scopeless. """Whether this Credentials object is scopeless.
@@ -1257,14 +1266,16 @@ class GoogleCredentials(OAuth2Credentials):
if not credentials_filename: if not credentials_filename:
return return
# If we can read the credentials from a file, we don't need to know what # If we can read the credentials from a file, we don't need to know
# environment we are in. # what environment we are in.
SETTINGS.env_name = DEFAULT_ENV_NAME SETTINGS.env_name = DEFAULT_ENV_NAME
try: try:
return _get_application_default_credential_from_file(credentials_filename) return _get_application_default_credential_from_file(
credentials_filename)
except (ApplicationDefaultCredentialsError, ValueError) as error: except (ApplicationDefaultCredentialsError, ValueError) as error:
_raise_exception_for_reading_json(credentials_filename, extra_help, error) _raise_exception_for_reading_json(credentials_filename,
extra_help, error)
@classmethod @classmethod
def _get_implicit_credentials(cls): def _get_implicit_credentials(cls):
@@ -1325,7 +1336,8 @@ class GoogleCredentials(OAuth2Credentials):
return _get_application_default_credential_from_file( return _get_application_default_credential_from_file(
credential_filename) credential_filename)
except (ApplicationDefaultCredentialsError, ValueError) as error: except (ApplicationDefaultCredentialsError, ValueError) as error:
extra_help = ' (provided as parameter to the from_stream() method)' extra_help = (' (provided as parameter to the '
'from_stream() method)')
_raise_exception_for_reading_json(credential_filename, _raise_exception_for_reading_json(credential_filename,
extra_help, extra_help,
error) error)
@@ -1384,7 +1396,8 @@ def _get_environment_variable_file():
return application_default_credential_filename return application_default_credential_filename
else: else:
raise ApplicationDefaultCredentialsError( raise ApplicationDefaultCredentialsError(
'File ' + application_default_credential_filename + ' (pointed by ' + 'File ' + application_default_credential_filename +
' (pointed by ' +
GOOGLE_APPLICATION_CREDENTIALS + GOOGLE_APPLICATION_CREDENTIALS +
' environment variable) does not exist!') ' environment variable) does not exist!')
@@ -1403,7 +1416,8 @@ def _get_well_known_file():
default_config_dir = os.path.join(os.environ['APPDATA'], default_config_dir = os.path.join(os.environ['APPDATA'],
_CLOUDSDK_CONFIG_DIRECTORY) _CLOUDSDK_CONFIG_DIRECTORY)
except KeyError: except KeyError:
# This should never happen unless someone is really messing with things. # This should never happen unless someone is really
# messing with things.
drive = os.environ.get('SystemDrive', 'C:') drive = os.environ.get('SystemDrive', 'C:')
default_config_dir = os.path.join(drive, '\\', default_config_dir = os.path.join(drive, '\\',
_CLOUDSDK_CONFIG_DIRECTORY) _CLOUDSDK_CONFIG_DIRECTORY)
@@ -1786,9 +1800,10 @@ def credentials_from_code(client_id, client_secret, scope, code,
access token access token
""" """
flow = OAuth2WebServerFlow(client_id, client_secret, scope, flow = OAuth2WebServerFlow(client_id, client_secret, scope,
redirect_uri=redirect_uri, user_agent=user_agent, redirect_uri=redirect_uri,
auth_uri=auth_uri, token_uri=token_uri, user_agent=user_agent, auth_uri=auth_uri,
revoke_uri=revoke_uri, device_uri=device_uri, token_uri=token_uri, revoke_uri=revoke_uri,
device_uri=device_uri,
token_info_uri=token_info_uri) token_info_uri=token_info_uri)
credentials = flow.step2_exchange(code, http=http) credentials = flow.step2_exchange(code, http=http)
@@ -1836,8 +1851,8 @@ def credentials_from_clientsecrets_and_code(filename, scope, code,
clientsecrets.InvalidClientSecretsError: if the clientsecrets file is clientsecrets.InvalidClientSecretsError: if the clientsecrets file is
invalid. invalid.
""" """
flow = flow_from_clientsecrets(filename, scope, message=message, cache=cache, flow = flow_from_clientsecrets(filename, scope, message=message,
redirect_uri=redirect_uri, cache=cache, redirect_uri=redirect_uri,
device_uri=device_uri) device_uri=device_uri)
credentials = flow.step2_exchange(code, http=http) credentials = flow.step2_exchange(code, http=http)
return credentials return credentials
@@ -1875,9 +1890,9 @@ class DeviceFlowInfo(collections.namedtuple('DeviceFlowInfo', (
'user_code_expiry': None, 'user_code_expiry': None,
}) })
if 'expires_in' in response: if 'expires_in' in response:
kwargs['user_code_expiry'] = datetime.datetime.now() + datetime.timedelta( kwargs['user_code_expiry'] = (
seconds=int(response['expires_in'])) datetime.datetime.now() +
datetime.timedelta(seconds=int(response['expires_in'])))
return cls(**kwargs) return cls(**kwargs)
@@ -1915,7 +1930,8 @@ class OAuth2WebServerFlow(Flow):
redirect_uri: string, Either the string 'urn:ietf:wg:oauth:2.0:oob' redirect_uri: string, Either the string 'urn:ietf:wg:oauth:2.0:oob'
for a non-web-based application, or a URI that for a non-web-based application, or a URI that
handles the callback from the authorization server. handles the callback from the authorization server.
user_agent: string, HTTP User-Agent to provide for this application. user_agent: string, HTTP User-Agent to provide for this
application.
auth_uri: string, URI for authorization endpoint. For convenience auth_uri: string, URI for authorization endpoint. For convenience
defaults to Google's endpoints but any OAuth 2.0 provider defaults to Google's endpoints but any OAuth 2.0 provider
can be used. can be used.
@@ -1982,8 +1998,9 @@ class OAuth2WebServerFlow(Flow):
if redirect_uri is not None: if redirect_uri is not None:
logger.warning(( logger.warning((
'The redirect_uri parameter for ' 'The redirect_uri parameter for '
'OAuth2WebServerFlow.step1_get_authorize_url is deprecated. Please ' 'OAuth2WebServerFlow.step1_get_authorize_url is deprecated. '
'move to passing the redirect_uri in via the constructor.')) 'Please move to passing the redirect_uri in via the '
'constructor.'))
self.redirect_uri = redirect_uri self.redirect_uri = redirect_uri
if self.redirect_uri is None: if self.redirect_uri is None:
@@ -2034,8 +2051,8 @@ class OAuth2WebServerFlow(Flow):
flow_info = json.loads(content) flow_info = json.loads(content)
except ValueError as e: except ValueError as e:
raise OAuth2DeviceCodeError( raise OAuth2DeviceCodeError(
'Could not parse server response as JSON: "%s", error: "%s"' % ( 'Could not parse server response as JSON: "%s", '
content, e)) 'error: "%s"' % (content, e))
return DeviceFlowInfo.FromResponse(flow_info) return DeviceFlowInfo.FromResponse(flow_info)
else: else:
error_msg = 'Invalid response %s.' % resp.status error_msg = 'Invalid response %s.' % resp.status
@@ -2044,7 +2061,8 @@ class OAuth2WebServerFlow(Flow):
if 'error' in d: if 'error' in d:
error_msg += ' Error: %s' % d['error'] error_msg += ' Error: %s' % d['error']
except ValueError: except ValueError:
# Couldn't decode a JSON response, stick with the default message. # Couldn't decode a JSON response, stick with the
# default message.
pass pass
raise OAuth2DeviceCodeError(error_msg) raise OAuth2DeviceCodeError(error_msg)
@@ -2120,27 +2138,27 @@ class OAuth2WebServerFlow(Flow):
"reauthenticating with approval_prompt='force'.") "reauthenticating with approval_prompt='force'.")
token_expiry = None token_expiry = None
if 'expires_in' in d: if 'expires_in' in d:
token_expiry = datetime.datetime.utcnow() + datetime.timedelta( token_expiry = (
seconds=int(d['expires_in'])) datetime.datetime.utcnow() +
datetime.timedelta(seconds=int(d['expires_in'])))
extracted_id_token = None extracted_id_token = None
if 'id_token' in d: if 'id_token' in d:
extracted_id_token = _extract_id_token(d['id_token']) extracted_id_token = _extract_id_token(d['id_token'])
logger.info('Successfully retrieved access token') logger.info('Successfully retrieved access token')
return OAuth2Credentials(access_token, self.client_id, return OAuth2Credentials(
self.client_secret, refresh_token, token_expiry, access_token, self.client_id, self.client_secret,
self.token_uri, self.user_agent, refresh_token, token_expiry, self.token_uri, self.user_agent,
revoke_uri=self.revoke_uri, revoke_uri=self.revoke_uri, id_token=extracted_id_token,
id_token=extracted_id_token, token_response=d, scopes=self.scope,
token_response=d,
scopes=self.scope,
token_info_uri=self.token_info_uri) token_info_uri=self.token_info_uri)
else: else:
logger.info('Failed to retrieve access token: %s', content) logger.info('Failed to retrieve access token: %s', content)
if 'error' in d: if 'error' in d:
# you never know what those providers got to say # you never know what those providers got to say
error_msg = str(d['error']) + str(d.get('error_description', '')) error_msg = (str(d['error']) +
str(d.get('error_description', '')))
else: else:
error_msg = 'Invalid response: %s.' % str(resp.status) error_msg = 'Invalid response: %s.' % str(resp.status)
raise FlowExchangeError(error_msg) raise FlowExchangeError(error_msg)
@@ -2187,8 +2205,10 @@ def flow_from_clientsecrets(filename, scope, redirect_uri=None,
invalid. invalid.
""" """
try: try:
client_type, client_info = clientsecrets.loadfile(filename, cache=cache) client_type, client_info = clientsecrets.loadfile(filename,
if client_type in (clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED): cache=cache)
if client_type in (clientsecrets.TYPE_WEB,
clientsecrets.TYPE_INSTALLED):
constructor_kwargs = { constructor_kwargs = {
'redirect_uri': redirect_uri, 'redirect_uri': redirect_uri,
'auth_uri': client_info['auth_uri'], 'auth_uri': client_info['auth_uri'],

View File

@@ -83,13 +83,14 @@ def _validate_clientsecrets(obj):
'"installed" application') '"installed" application')
client_type = tuple(obj)[0] client_type = tuple(obj)[0]
if client_type not in VALID_CLIENT: if client_type not in VALID_CLIENT:
raise InvalidClientSecretsError('Unknown client type: %s.' % (client_type, )) raise InvalidClientSecretsError(
'Unknown client type: %s.' % (client_type,))
client_info = obj[client_type] client_info = obj[client_type]
for prop_name in VALID_CLIENT[client_type]['required']: for prop_name in VALID_CLIENT[client_type]['required']:
if prop_name not in client_info: if prop_name not in client_info:
raise InvalidClientSecretsError( raise InvalidClientSecretsError(
'Missing property "%s" in a client type of "%s".' % (prop_name, 'Missing property "%s" in a client type of "%s".' %
client_type)) (prop_name, client_type))
for prop_name in VALID_CLIENT[client_type]['string']: for prop_name in VALID_CLIENT[client_type]['string']:
if client_info[prop_name].startswith('[['): if client_info[prop_name].startswith('[['):
raise InvalidClientSecretsError( raise InvalidClientSecretsError(

View File

@@ -45,11 +45,9 @@ except ImportError:
OpenSSLVerifier = None OpenSSLVerifier = None
OpenSSLSigner = None OpenSSLSigner = None
def pkcs12_key_as_pem(*args, **kwargs): def pkcs12_key_as_pem(*args, **kwargs):
raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.') raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.')
try: try:
from oauth2client._pycrypto_crypt import PyCryptoVerifier from oauth2client._pycrypto_crypt import PyCryptoVerifier
from oauth2client._pycrypto_crypt import PyCryptoSigner from oauth2client._pycrypto_crypt import PyCryptoSigner

View File

@@ -35,8 +35,9 @@ class CommunicationError(Error):
class NoDevshellServer(Error): class NoDevshellServer(Error):
"""Error when no Developer Shell server can be contacted.""" """Error when no Developer Shell server can be contacted."""
# The request for credential information to the Developer Shell client socket is # The request for credential information to the Developer Shell client socket
# always an empty PBLite-formatted JSON object, so just define it as a constant. # is always an empty PBLite-formatted JSON object, so just define it as a
# constant.
CREDENTIAL_INFO_REQUEST_JSON = '[]' CREDENTIAL_INFO_REQUEST_JSON = '[]'
@@ -44,7 +45,9 @@ class CredentialInfoResponse(object):
"""Credential information response from Developer Shell server. """Credential information response from Developer Shell server.
The credential information response from Developer Shell socket is a The credential information response from Developer Shell socket is a
PBLite-formatted JSON array with fields encoded by their index in the array: PBLite-formatted JSON array with fields encoded by their index in the
array:
* Index 0 - user email * Index 0 - user email
* Index 1 - default project ID. None if the project context is not known. * Index 1 - default project ID. None if the project context is not known.
* Index 2 - OAuth2 access token. None if there is no valid auth context. * Index 2 - OAuth2 access token. None if there is no valid auth context.

View File

@@ -93,7 +93,8 @@ class Storage(BaseStorage):
Args: Args:
model: db.Model, model class model: db.Model, model class
key_name: string, key name for the entity that has the credentials key_name: string, key name for the entity that has the credentials
key_value: string, key value for the entity that has the credentials key_value: string, key value for the entity that has the
credentials
property_name: string, name of the property that is an property_name: string, name of the property that is an
CredentialsProperty CredentialsProperty
""" """
@@ -124,12 +125,14 @@ class Storage(BaseStorage):
Args: Args:
credentials: Credentials, the credentials to store. credentials: Credentials, the credentials to store.
overwrite: Boolean, indicates whether you would like these overwrite: Boolean, indicates whether you would like these
credentials to overwrite any existing stored credentials. credentials to overwrite any existing stored
credentials.
""" """
args = {self.key_name: self.key_value} args = {self.key_name: self.key_value}
if overwrite: if overwrite:
entity, unused_is_new = self.model_class.objects.get_or_create(**args) (entity,
unused_is_new) = self.model_class.objects.get_or_create(**args)
else: else:
entity = self.model_class(**args) entity = self.model_class(**args)

View File

@@ -46,8 +46,8 @@ apiui/credential>`__.
Usage Usage
===== =====
Once configured, you can use the :meth:`UserOAuth2.required` decorator to ensure Once configured, you can use the :meth:`UserOAuth2.required` decorator to
that credentials are available within a view. ensure that credentials are available within a view.
.. code-block:: python .. code-block:: python
:emphasize-lines: 3,7,10 :emphasize-lines: 3,7,10
@@ -291,8 +291,9 @@ class UserOAuth2(object):
raise ValueError( raise ValueError(
'OAuth2 configuration could not be found. Either specify the ' 'OAuth2 configuration could not be found. Either specify the '
'client_secrets_file or client_id and client_secret or set the' 'client_secrets_file or client_id and client_secret or set the'
'app configuration variables GOOGLE_OAUTH2_CLIENT_SECRETS_FILE ' 'app configuration variables '
'or GOOGLE_OAUTH2_CLIENT_ID and GOOGLE_OAUTH2_CLIENT_SECRET.') 'GOOGLE_OAUTH2_CLIENT_SECRETS_FILE or '
'GOOGLE_OAUTH2_CLIENT_ID and GOOGLE_OAUTH2_CLIENT_SECRET.')
def _load_client_secrets(self, filename): def _load_client_secrets(self, filename):
"""Loads client secrets from the given filename.""" """Loads client secrets from the given filename."""
@@ -392,7 +393,8 @@ class UserOAuth2(object):
credentials = flow.step2_exchange(code) credentials = flow.step2_exchange(code)
except FlowExchangeError as exchange_error: except FlowExchangeError as exchange_error:
current_app.logger.exception(exchange_error) current_app.logger.exception(exchange_error)
return 'An error occurred: %s' % exchange_error, httplib.BAD_REQUEST content = 'An error occurred: %s' % (exchange_error,)
return content, httplib.BAD_REQUEST
# Save the credentials to the storage. # Save the credentials to the storage.
self.storage.put(credentials) self.storage.put(credentials)
@@ -420,9 +422,9 @@ class UserOAuth2(object):
def email(self): def email(self):
"""Returns the user's email address or None if there are no credentials. """Returns the user's email address or None if there are no credentials.
The email address is provided by the current credentials' id_token. This The email address is provided by the current credentials' id_token.
should not be used as unique identifier as the user can change their This should not be used as unique identifier as the user can change
email. If you need a unique identifier, use user_id. their email. If you need a unique identifier, use user_id.
""" """
if not self.credentials: if not self.credentials:
return None return None
@@ -451,8 +453,9 @@ class UserOAuth2(object):
def authorize_url(self, return_url, **kwargs): def authorize_url(self, return_url, **kwargs):
"""Creates a URL that can be used to start the authorization flow. """Creates a URL that can be used to start the authorization flow.
When the user is directed to the URL, the authorization flow will begin. When the user is directed to the URL, the authorization flow will
Once complete, the user will be redirected to the specified return URL. begin. Once complete, the user will be redirected to the specified
return URL.
Any kwargs are passed into the flow constructor. Any kwargs are passed into the flow constructor.
""" """

View File

@@ -44,9 +44,9 @@ class AppAssertionCredentials(AssertionCredentials):
used for the purpose of accessing data stored under an account assigned to used for the purpose of accessing data stored under an account assigned to
the Compute Engine instance itself. the Compute Engine instance itself.
This credential does not require a flow to instantiate because it represents This credential does not require a flow to instantiate because it
a two legged flow, and therefore has all of the required information to represents a two legged flow, and therefore has all of the required
generate and refresh its own access tokens. information to generate and refresh its own access tokens.
""" """
@util.positional(2) @util.positional(2)
@@ -60,7 +60,8 @@ class AppAssertionCredentials(AssertionCredentials):
self.scope = util.scopes_to_string(scope) self.scope = util.scopes_to_string(scope)
self.kwargs = kwargs self.kwargs = kwargs
# Assertion type is no longer used, but still in the parent class signature. # Assertion type is no longer used, but still in the
# parent class signature.
super(AppAssertionCredentials, self).__init__(None) super(AppAssertionCredentials, self).__init__(None)
@classmethod @classmethod
@@ -74,9 +75,9 @@ class AppAssertionCredentials(AssertionCredentials):
Skip all the storage hoops and just refresh using the API. Skip all the storage hoops and just refresh using the API.
Args: Args:
http_request: callable, a callable that matches the method signature http_request: callable, a callable that matches the method
of httplib2.Http.request, used to make the refresh signature of httplib2.Http.request, used to make
request. the refresh request.
Raises: Raises:
AccessTokenRefreshError: When the refresh fails. AccessTokenRefreshError: When the refresh fails.

View File

@@ -176,7 +176,6 @@ class _PosixOpener(_Opener):
try: try:
import fcntl import fcntl
class _FcntlOpener(_Opener): class _FcntlOpener(_Opener):
"""Open, lock, and unlock a file using fcntl.lockf.""" """Open, lock, and unlock a file using fcntl.lockf."""
@@ -190,7 +189,8 @@ try:
Raises: Raises:
AlreadyLockedException: if the lock is already acquired. AlreadyLockedException: if the lock is already acquired.
IOError: if the open fails. IOError: if the open fails.
CredentialsFileSymbolicLinkError if the file is a symbolic link. CredentialsFileSymbolicLinkError: if the file is a symbolic
link.
""" """
if self._locked: if self._locked:
raise AlreadyLockedException('File %s is already locked' % raise AlreadyLockedException('File %s is already locked' %
@@ -201,7 +201,8 @@ try:
try: try:
self._fh = open(self._filename, self._mode) self._fh = open(self._filename, self._mode)
except IOError as e: except IOError as e:
# If we can't access with _mode, try _fallback_mode and don't lock. # If we can't access with _mode, try _fallback_mode and
# don't lock.
if e.errno in (errno.EPERM, errno.EACCES): if e.errno in (errno.EPERM, errno.EACCES):
self._fh = open(self._filename, self._fallback_mode) self._fh = open(self._filename, self._fallback_mode)
return return
@@ -244,7 +245,6 @@ try:
import win32con import win32con
import win32file import win32file
class _Win32Opener(_Opener): class _Win32Opener(_Opener):
"""Open, lock, and unlock a file using windows primitives.""" """Open, lock, and unlock a file using windows primitives."""
@@ -278,7 +278,8 @@ try:
try: try:
self._fh = open(self._filename, self._mode) self._fh = open(self._filename, self._mode)
except IOError as e: except IOError as e:
# If we can't access with _mode, try _fallback_mode and don't lock. # If we can't access with _mode, try _fallback_mode
# and don't lock.
if e.errno == errno.EACCES: if e.errno == errno.EACCES:
self._fh = open(self._filename, self._fallback_mode) self._fh = open(self._filename, self._fallback_mode)
return return
@@ -298,7 +299,8 @@ try:
if timeout == 0: if timeout == 0:
raise raise
# If the error is not that the file is already in use, raise. # If the error is not that the file is already
# in use, raise.
if e[0] != _Win32Opener.FILE_IN_USE_ERROR: if e[0] != _Win32Opener.FILE_IN_USE_ERROR:
raise raise
@@ -317,7 +319,8 @@ try:
if self._locked: if self._locked:
try: try:
hfile = win32file._get_osfhandle(self._fh.fileno()) hfile = win32file._get_osfhandle(self._fh.fileno())
win32file.UnlockFileEx(hfile, 0, -0x10000, pywintypes.OVERLAPPED()) win32file.UnlockFileEx(hfile, 0, -0x10000,
pywintypes.OVERLAPPED())
except pywintypes.error as e: except pywintypes.error as e:
if e[0] != _Win32Opener.FILE_ALREADY_UNLOCKED_ERROR: if e[0] != _Win32Opener.FILE_ALREADY_UNLOCKED_ERROR:
raise raise

View File

@@ -97,8 +97,8 @@ def get_credential_storage(filename, client_id, user_agent, scope,
@util.positional(2) @util.positional(2)
def get_credential_storage_custom_string_key( def get_credential_storage_custom_string_key(filename, key_string,
filename, key_string, warn_on_readonly=True): warn_on_readonly=True):
"""Get a Storage instance for a credential using a single string as a key. """Get a Storage instance for a credential using a single string as a key.
Allows you to provide a string as a custom key that will be used for Allows you to provide a string as a custom key that will be used for
@@ -120,8 +120,8 @@ def get_credential_storage_custom_string_key(
@util.positional(2) @util.positional(2)
def get_credential_storage_custom_key( def get_credential_storage_custom_key(filename, key_dict,
filename, key_dict, warn_on_readonly=True): warn_on_readonly=True):
"""Get a Storage instance for a credential using a dictionary as a key. """Get a Storage instance for a credential using a dictionary as a key.
Allows you to provide a dictionary as a custom key that will be used for Allows you to provide a dictionary as a custom key that will be used for
@@ -211,7 +211,7 @@ class _MultiStore(object):
self._data = None self._data = None
class _Storage(BaseStorage): class _Storage(BaseStorage):
"""A Storage object that knows how to read/write a single credential.""" """A Storage object that can read/write a single credential."""
def __init__(self, multistore, key): def __init__(self, multistore, key):
self._multistore = multistore self._multistore = multistore
@@ -285,8 +285,8 @@ class _MultiStore(object):
self._file.open_and_lock() self._file.open_and_lock()
except IOError as e: except IOError as e:
if e.errno == errno.ENOSYS: if e.errno == errno.ENOSYS:
logger.warn('File system does not support locking the credentials ' logger.warn('File system does not support locking the '
'file.') 'credentials file.')
elif e.errno == errno.ENOLCK: elif e.errno == errno.ENOLCK:
logger.warn('File system is out of resources for writing the ' logger.warn('File system is out of resources for writing the '
'credentials file (is your disk full?).') 'credentials file (is your disk full?).')
@@ -295,8 +295,9 @@ class _MultiStore(object):
if not self._file.is_locked(): if not self._file.is_locked():
self._read_only = True self._read_only = True
if self._warn_on_readonly: if self._warn_on_readonly:
logger.warn('The credentials file (%s) is not writable. Opening in ' logger.warn('The credentials file (%s) is not writable. '
'read-only mode. Any refreshed credentials will only be ' 'Opening in read-only mode. Any refreshed '
'credentials will only be '
'valid for this run.', self._file.filename()) 'valid for this run.', self._file.filename())
if os.path.getsize(self._file.filename()) == 0: if os.path.getsize(self._file.filename()) == 0:
logger.debug('Initializing empty multistore file') logger.debug('Initializing empty multistore file')
@@ -340,7 +341,8 @@ class _MultiStore(object):
if self._read_only: if self._read_only:
return return
self._file.file_handle().seek(0) self._file.file_handle().seek(0)
json.dump(data, self._file.file_handle(), sort_keys=True, indent=2, separators=(',', ': ')) json.dump(data, self._file.file_handle(),
sort_keys=True, indent=2, separators=(',', ': '))
self._file.file_handle().truncate() self._file.file_handle().truncate()
def _refresh_data_cache(self): def _refresh_data_cache(self):
@@ -379,11 +381,12 @@ class _MultiStore(object):
for cred_entry in credentials: for cred_entry in credentials:
try: try:
(key, credential) = self._decode_credential_from_json(cred_entry) key, credential = self._decode_credential_from_json(cred_entry)
self._data[key] = credential self._data[key] = credential
except: except:
# If something goes wrong loading a credential, just ignore it # If something goes wrong loading a credential, just ignore it
logger.info('Error decoding credential, skipping', exc_info=True) logger.info('Error decoding credential, skipping',
exc_info=True)
def _decode_credential_from_json(self, cred_entry): def _decode_credential_from_json(self, cred_entry):
"""Load a credential from our JSON serialization. """Load a credential from our JSON serialization.
@@ -398,7 +401,8 @@ class _MultiStore(object):
raw_key = cred_entry['key'] raw_key = cred_entry['key']
key = util.dict_to_tuple_key(raw_key) key = util.dict_to_tuple_key(raw_key)
credential = None credential = None
credential = Credentials.new_from_json(json.dumps(cred_entry['credential'])) credential = Credentials.new_from_json(
json.dumps(cred_entry['credential']))
return (key, credential) return (key, credential)
def _write(self): def _write(self):

View File

@@ -72,7 +72,8 @@ def run(flow, storage, http=None):
of values. of values.
``--[no]auth_local_webserver`` (boolean, default: ``True``) ``--[no]auth_local_webserver`` (boolean, default: ``True``)
Run a local web server to handle redirects during OAuth authorization. Run a local web server to handle redirects during OAuth
authorization.
Since it uses flags make sure to initialize the ``gflags`` module before Since it uses flags make sure to initialize the ``gflags`` module before
calling ``run()``. calling ``run()``.
@@ -87,8 +88,8 @@ def run(flow, storage, http=None):
Credentials, the obtained credential. Credentials, the obtained credential.
""" """
logging.warning('This function, oauth2client.tools.run(), and the use of ' logging.warning('This function, oauth2client.tools.run(), and the use of '
'the gflags library are deprecated and will be removed in a future ' 'the gflags library are deprecated and will be removed in '
'version of the library.') 'a future version of the library.')
if FLAGS.auth_local_webserver: if FLAGS.auth_local_webserver:
success = False success = False
port_number = 0 port_number = 0
@@ -104,7 +105,8 @@ def run(flow, storage, http=None):
break break
FLAGS.auth_local_webserver = success FLAGS.auth_local_webserver = success
if not success: if not success:
print('Failed to start a local webserver listening on either port 8080') print('Failed to start a local webserver listening on '
'either port 8080')
print('or port 9090. Please check your firewall settings and locally') print('or port 9090. Please check your firewall settings and locally')
print('running programs that may be blocking or using those ports.') print('running programs that may be blocking or using those ports.')
print() print()
@@ -144,7 +146,8 @@ def run(flow, storage, http=None):
if 'code' in httpd.query_params: if 'code' in httpd.query_params:
code = httpd.query_params['code'] code = httpd.query_params['code']
else: else:
print('Failed to find "code" in the query parameters of the redirect.') print('Failed to find "code" in the query '
'parameters of the redirect.')
sys.exit('Try running with --noauth_local_webserver.') sys.exit('Try running with --noauth_local_webserver.')
else: else:
code = input('Enter verification code: ').strip() code = input('Enter verification code: ').strip()

View File

@@ -38,13 +38,14 @@ class _ServiceAccountCredentials(AssertionCredentials):
MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
def __init__(self, service_account_id, service_account_email, private_key_id, def __init__(self, service_account_id, service_account_email,
private_key_pkcs8_text, scopes, user_agent=None, private_key_id, private_key_pkcs8_text, scopes,
token_uri=GOOGLE_TOKEN_URI, revoke_uri=GOOGLE_REVOKE_URI, user_agent=None, token_uri=GOOGLE_TOKEN_URI,
**kwargs): revoke_uri=GOOGLE_REVOKE_URI, **kwargs):
super(_ServiceAccountCredentials, self).__init__( super(_ServiceAccountCredentials, self).__init__(
None, user_agent=user_agent, token_uri=token_uri, revoke_uri=revoke_uri) None, user_agent=user_agent, token_uri=token_uri,
revoke_uri=revoke_uri)
self._service_account_id = service_account_id self._service_account_id = service_account_id
self._service_account_email = service_account_email self._service_account_email = service_account_email
@@ -81,7 +82,8 @@ class _ServiceAccountCredentials(AssertionCredentials):
assertion_input = first_segment + b'.' + second_segment assertion_input = first_segment + b'.' + second_segment
# Sign the assertion. # Sign the assertion.
rsa_bytes = rsa.pkcs1.sign(assertion_input, self._private_key, 'SHA-256') rsa_bytes = rsa.pkcs1.sign(assertion_input, self._private_key,
'SHA-256')
signature = base64.urlsafe_b64encode(rsa_bytes).rstrip(b'=') signature = base64.urlsafe_b64encode(rsa_bytes).rstrip(b'=')
return assertion_input + b'.' + signature return assertion_input + b'.' + signature

View File

@@ -60,7 +60,8 @@ def _CreateArgumentParser():
default=False, help='Do not run a local web server.') default=False, help='Do not run a local web server.')
parser.add_argument('--auth_host_port', default=[8080, 8090], type=int, parser.add_argument('--auth_host_port', default=[8080, 8090], type=int,
nargs='*', help='Port web server should listen on.') nargs='*', help='Port web server should listen on.')
parser.add_argument('--logging_level', default='ERROR', parser.add_argument(
'--logging_level', default='ERROR',
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
help='Set the logging level of detail.') help='Set the logging level of detail.')
return parser return parser
@@ -100,12 +101,14 @@ class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
query = self.path.split('?', 1)[-1] query = self.path.split('?', 1)[-1]
query = dict(urllib.parse.parse_qsl(query)) query = dict(urllib.parse.parse_qsl(query))
self.server.query_params = query self.server.query_params = query
self.wfile.write(b"<html><head><title>Authentication Status</title></head>") self.wfile.write(
self.wfile.write(b"<body><p>The authentication flow has completed.</p>") b"<html><head><title>Authentication Status</title></head>")
self.wfile.write(
b"<body><p>The authentication flow has completed.</p>")
self.wfile.write(b"</body></html>") self.wfile.write(b"</body></html>")
def log_message(self, format, *args): def log_message(self, format, *args):
"""Do not log messages to stdout while running as command line program.""" """Do not log messages to stdout while running as cmd. line program."""
@util.positional(3) @util.positional(3)
@@ -137,9 +140,9 @@ def run_flow(flow, storage, flags, http=None):
Run a local web server to handle redirects during OAuth Run a local web server to handle redirects during OAuth
authorization. authorization.
The tools module defines an ``ArgumentParser`` the already contains the flag The tools module defines an ``ArgumentParser`` the already contains the
definitions that ``run()`` requires. You can pass that ``ArgumentParser`` to flag definitions that ``run()`` requires. You can pass that
your ``ArgumentParser`` constructor:: ``ArgumentParser`` to your ``ArgumentParser`` constructor::
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=__doc__, description=__doc__,
@@ -175,7 +178,8 @@ def run_flow(flow, storage, flags, http=None):
break break
flags.noauth_local_webserver = not success flags.noauth_local_webserver = not success
if not success: if not success:
print('Failed to start a local webserver listening on either port 8080') print('Failed to start a local webserver listening '
'on either port 8080')
print('or port 9090. Please check your firewall settings and locally') print('or port 9090. Please check your firewall settings and locally')
print('running programs that may be blocking or using those ports.') print('running programs that may be blocking or using those ports.')
print() print()
@@ -197,7 +201,8 @@ def run_flow(flow, storage, flags, http=None):
print() print()
print(' ' + authorize_url) print(' ' + authorize_url)
print() print()
print('If your browser is on a different machine then exit and re-run this') print('If your browser is on a different machine then '
'exit and re-run this')
print('application with the command-line parameter ') print('application with the command-line parameter ')
print() print()
print(' --noauth_local_webserver') print(' --noauth_local_webserver')
@@ -216,7 +221,8 @@ def run_flow(flow, storage, flags, http=None):
if 'code' in httpd.query_params: if 'code' in httpd.query_params:
code = httpd.query_params['code'] code = httpd.query_params['code']
else: else:
print('Failed to find "code" in the query parameters of the redirect.') print('Failed to find "code" in the query parameters '
'of the redirect.')
sys.exit('Try running with --noauth_local_webserver.') sys.exit('Try running with --noauth_local_webserver.')
else: else:
code = input('Enter verification code: ').strip() code = input('Enter verification code: ').strip()
@@ -235,9 +241,9 @@ def run_flow(flow, storage, flags, http=None):
def message_if_missing(filename): def message_if_missing(filename):
"""Helpful message to display if the CLIENT_SECRETS file is missing.""" """Helpful message to display if the CLIENT_SECRETS file is missing."""
return _CLIENT_SECRETS_MESSAGE % filename return _CLIENT_SECRETS_MESSAGE % filename
try: try:
from oauth2client.old_run import run from oauth2client.old_run import run
from oauth2client.old_run import FLAGS from oauth2client.old_run import FLAGS

View File

@@ -129,8 +129,10 @@ def positional(max_positional_args):
plural_s = '' plural_s = ''
if max_positional_args != 1: if max_positional_args != 1:
plural_s = 's' plural_s = 's'
message = '%s() takes at most %d positional argument%s (%d given)' % ( message = ('%s() takes at most %d positional '
wrapped.__name__, max_positional_args, plural_s, len(args)) 'argument%s (%d given)' % (
wrapped.__name__, max_positional_args,
plural_s, len(args)))
if positional_parameters_enforcement == POSITIONAL_EXCEPTION: if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
raise TypeError(message) raise TypeError(message)
elif positional_parameters_enforcement == POSITIONAL_WARNING: elif positional_parameters_enforcement == POSITIONAL_WARNING: