From d7c0c38b8d9c20fc24f5bd1bc8a368888025440d Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Thu, 20 Aug 2015 16:08:20 -0700 Subject: [PATCH] Making oauth2client/ files pass PEP8. --- oauth2client/_helpers.py | 8 +- oauth2client/_openssl_crypt.py | 4 +- oauth2client/_pycrypto_crypt.py | 15 +- oauth2client/appengine.py | 177 ++++++------ oauth2client/client.py | 488 +++++++++++++++++--------------- oauth2client/clientsecrets.py | 21 +- oauth2client/crypt.py | 10 +- oauth2client/devshell.py | 27 +- oauth2client/django_orm.py | 9 +- oauth2client/file.py | 2 +- oauth2client/flask_util.py | 25 +- oauth2client/gce.py | 21 +- oauth2client/keyring_storage.py | 2 +- oauth2client/locked_file.py | 43 +-- oauth2client/multistore_file.py | 46 +-- oauth2client/old_run.py | 27 +- oauth2client/service_account.py | 62 ++-- oauth2client/tools.py | 58 ++-- oauth2client/util.py | 6 +- oauth2client/xsrfutil.py | 2 +- 20 files changed, 558 insertions(+), 495 deletions(-) diff --git a/oauth2client/_helpers.py b/oauth2client/_helpers.py index f252bf5..39bfeb6 100644 --- a/oauth2client/_helpers.py +++ b/oauth2client/_helpers.py @@ -63,11 +63,11 @@ def _to_bytes(value, encoding='ascii'): ValueError if the value could not be converted to bytes. """ result = (value.encode(encoding) - if isinstance(value, six.text_type) else value) + if isinstance(value, six.text_type) else value) if isinstance(result, six.binary_type): return result else: - raise ValueError('%r could not be converted to bytes' % (value, )) + raise ValueError('%r could not be converted to bytes' % (value,)) def _from_bytes(value): @@ -84,11 +84,11 @@ def _from_bytes(value): ValueError if the value could not be converted to unicode. """ result = (value.decode('utf-8') - if isinstance(value, six.binary_type) else value) + if isinstance(value, six.binary_type) else value) if isinstance(result, six.text_type): return result else: - raise ValueError('%r could not be converted to unicode' % (value, )) + raise ValueError('%r could not be converted to unicode' % (value,)) def _urlsafe_b64encode(raw_bytes): diff --git a/oauth2client/_openssl_crypt.py b/oauth2client/_openssl_crypt.py index 9896f62..aca3505 100644 --- a/oauth2client/_openssl_crypt.py +++ b/oauth2client/_openssl_crypt.py @@ -54,7 +54,7 @@ class OpenSSLVerifier(object): return False @staticmethod - def from_string(key_pem, is_x509_cert): + def from_string(key_pem, is_x509_cert): """Construct a Verified instance from a string. Args: @@ -136,4 +136,4 @@ def pkcs12_key_as_pem(private_key_text, private_key_password): pkcs12 = crypto.load_pkcs12(decoded_body, private_key_password) return crypto.dump_privatekey(crypto.FILETYPE_PEM, - pkcs12.get_privatekey()) + pkcs12.get_privatekey()) diff --git a/oauth2client/_pycrypto_crypt.py b/oauth2client/_pycrypto_crypt.py index e604095..fa02575 100644 --- a/oauth2client/_pycrypto_crypt.py +++ b/oauth2client/_pycrypto_crypt.py @@ -50,7 +50,7 @@ class PyCryptoVerifier(object): """ message = _to_bytes(message, encoding='utf-8') return PKCS1_v1_5.new(self._pubkey).verify( - SHA256.new(message), signature) + SHA256.new(message), signature) @staticmethod def from_string(key_pem, is_x509_cert): @@ -58,8 +58,8 @@ class PyCryptoVerifier(object): Args: key_pem: string, public key in PEM format. - is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is - expected to be an RSA key in PEM format. + is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it + is expected to be an RSA key in PEM format. Returns: Verifier instance. @@ -121,8 +121,9 @@ class PyCryptoSigner(object): pkey = RSA.importKey(parsed_pem_key) else: raise NotImplementedError( - 'PKCS12 format is not supported by the PyCrypto library. ' - 'Try converting to a "PEM" ' - '(openssl pkcs12 -in xxxxx.p12 -nodes -nocerts > privatekey.pem) ' - 'or using PyOpenSSL if native code is an option.') + 'PKCS12 format is not supported by the PyCrypto library. ' + 'Try converting to a "PEM" ' + '(openssl pkcs12 -in xxxxx.p12 -nodes -nocerts > ' + 'privatekey.pem) ' + 'or using PyOpenSSL if native code is an option.') return PyCryptoSigner(pkey) diff --git a/oauth2client/appengine.py b/oauth2client/appengine.py index 5434063..47d390c 100644 --- a/oauth2client/appengine.py +++ b/oauth2client/appengine.py @@ -132,7 +132,8 @@ def xsrf_secret_key(): model.secret = _generate_new_xsrf_secret_key() model.put() secret = model.secret - memcache.add(XSRF_MEMCACHE_ID, secret, namespace=OAUTH2CLIENT_NAMESPACE) + memcache.add(XSRF_MEMCACHE_ID, secret, + namespace=OAUTH2CLIENT_NAMESPACE) return str(secret) @@ -166,7 +167,8 @@ class AppAssertionCredentials(AssertionCredentials): self._kwargs = kwargs 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) @classmethod @@ -192,14 +194,15 @@ class AppAssertionCredentials(AssertionCredentials): try: scopes = self.scope.split() (token, _) = app_identity.get_access_token( - scopes, service_account_id=self.service_account_id) + scopes, service_account_id=self.service_account_id) except app_identity.Error as e: raise AccessTokenRefreshError(str(e)) self.access_token = token @property 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): return not self.scope @@ -220,8 +223,8 @@ class FlowProperty(db.Property): # For writing to datastore. def get_value_for_datastore(self, model_instance): - flow = super(FlowProperty, - self).get_value_for_datastore(model_instance) + flow = super(FlowProperty, self).get_value_for_datastore( + model_instance) return db.Blob(pickle.dumps(flow)) # For reading from datastore. @@ -233,8 +236,8 @@ class FlowProperty(db.Property): def validate(self, value): if value is not None and not isinstance(value, Flow): raise db.BadValueError('Property %s must be convertible ' - 'to a FlowThreeLegged instance (%s)' % - (self.name, value)) + 'to a FlowThreeLegged instance (%s)' % + (self.name, value)) return super(FlowProperty, self).validate(value) def empty(self, value): @@ -266,7 +269,8 @@ if ndb is not None: logger.info('validate: Got type %s', type(value)) if value is not None and not isinstance(value, 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): @@ -282,8 +286,8 @@ class CredentialsProperty(db.Property): # For writing to datastore. def get_value_for_datastore(self, model_instance): logger.info("get: Got type " + str(type(model_instance))) - cred = super(CredentialsProperty, - self).get_value_for_datastore(model_instance) + cred = super(CredentialsProperty, self).get_value_for_datastore( + model_instance) if cred is None: cred = '' else: @@ -308,16 +312,12 @@ class CredentialsProperty(db.Property): logger.info("validate: Got type " + str(type(value))) if value is not None and not isinstance(value, Credentials): raise db.BadValueError('Property %s must be convertible ' - 'to a Credentials instance (%s)' % - (self.name, value)) - #if value is not None and not isinstance(value, Credentials): - # return None + 'to a Credentials instance (%s)' % + (self.name, value)) return value if ndb is not None: - - # TODO(dhermes): Turn this into a JsonProperty and overhaul the Credentials # and subclass mechanics to use new_from_dict, to_dict, # from_dict, etc. @@ -344,8 +344,9 @@ if ndb is not None: """ logger.info('validate: Got type %s', type(value)) if value is not None and not isinstance(value, Credentials): - raise TypeError('Property %s must be convertible to a credentials ' - 'instance; received: %s.' % (self._name, value)) + raise TypeError('Property %s must be convertible to a ' + 'credentials instance; received: %s.' % + (self._name, value)) def _to_base_type(self, value): """Converts our validated value to a JSON serialized string. @@ -409,7 +410,8 @@ class StorageByKeyName(Storage): """ if key_name 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() self._model = model @@ -423,15 +425,17 @@ class StorageByKeyName(Storage): Returns: 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 - # worry about new-style classes since ndb and db models are new-style + # issubclass will fail if one of the arguments is not a class, only + # need worry about new-style classes since ndb and db models are + # new-style if isinstance(self._model, type): if ndb is not None and issubclass(self._model, ndb.Model): return True elif issubclass(self._model, db.Model): 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): """Retrieve entity from datastore. @@ -460,7 +464,7 @@ class StorageByKeyName(Storage): db.delete(entity_key) @db.non_transactional(allow_existing=True) - def locked_get(self): + def locked_get(self): """Retrieve Credential from datastore. Returns: @@ -496,7 +500,7 @@ class StorageByKeyName(Storage): self._cache.set(self._key_name, credentials.to_json()) @db.non_transactional(allow_existing=True) - def locked_delete(self): + def locked_delete(self): """Delete Credential from datastore.""" if self._cache: @@ -548,8 +552,8 @@ def _build_state_value(request_handler, user): """ uri = request_handler.request.url token = xsrfutil.generate_token(xsrf_secret_key(), user.user_id(), - action_id=str(uri)) - return uri + ':' + token + action_id=str(uri)) + return uri + ':' + token def _parse_state_value(state, user): @@ -569,7 +573,7 @@ def _parse_state_value(state, user): """ uri, token = state.rsplit(':', 1) if not xsrfutil.validate_token(xsrf_secret_key(), token, user.user_id(), - action_id=uri): + action_id=uri): raise InvalidXsrfTokenError() return uri @@ -629,18 +633,17 @@ class OAuth2Decorator(object): @util.positional(4) def __init__(self, client_id, client_secret, scope, - auth_uri=GOOGLE_AUTH_URI, - token_uri=GOOGLE_TOKEN_URI, - revoke_uri=GOOGLE_REVOKE_URI, - user_agent=None, - message=None, - callback_path='/oauth2callback', - token_response_param=None, - _storage_class=StorageByKeyName, - _credentials_class=CredentialsModel, - _credentials_property_name='credentials', - **kwargs): - + auth_uri=GOOGLE_AUTH_URI, + token_uri=GOOGLE_TOKEN_URI, + revoke_uri=GOOGLE_REVOKE_URI, + user_agent=None, + message=None, + callback_path='/oauth2callback', + token_response_param=None, + _storage_class=StorageByKeyName, + _credentials_class=CredentialsModel, + _credentials_property_name='credentials', + **kwargs): """Constructor for OAuth2Decorator Args: @@ -659,13 +662,14 @@ class OAuth2Decorator(object): provider can be used. user_agent: string, User agent of your application, default to None. - message: Message to display if there are problems with the OAuth 2.0 - configuration. The message may contain HTML and will be - presented on the web interface for any method that uses - the decorator. + message: Message to display if there are problems with the + OAuth 2.0 configuration. The message may contain HTML and + will be presented on the web interface for any method that + uses the decorator. callback_path: string, The absolute path to use as the callback 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 to the access token request will be encoded and included in this query parameter in the @@ -730,19 +734,21 @@ class OAuth2Decorator(object): return 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: request_handler.redirect(users.create_login_url( - request_handler.request.uri)) + request_handler.request.uri)) return self._create_flow(request_handler) # 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_class, None, - self._credentials_property_name, user=user).get() + self._credentials_class, None, + self._credentials_property_name, user=user).get() if not self.has_credentials(): return request_handler.redirect(self.authorize_url()) @@ -768,14 +774,12 @@ class OAuth2Decorator(object): """ if self.flow is None: redirect_uri = request_handler.request.relative_url( - self._callback_path) # Usually /oauth2callback - self.flow = OAuth2WebServerFlow(self._client_id, self._client_secret, - self._scope, redirect_uri=redirect_uri, - user_agent=self._user_agent, - auth_uri=self._auth_uri, - token_uri=self._token_uri, - revoke_uri=self._revoke_uri, - **self._kwargs) + self._callback_path) # Usually /oauth2callback + self.flow = OAuth2WebServerFlow( + self._client_id, self._client_secret, self._scope, + redirect_uri=redirect_uri, user_agent=self._user_agent, + auth_uri=self._auth_uri, token_uri=self._token_uri, + revoke_uri=self._revoke_uri, **self._kwargs) def oauth_aware(self, method): """Decorator that sets up for OAuth 2.0 dance, but doesn't do it. @@ -797,18 +801,20 @@ class OAuth2Decorator(object): return 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: request_handler.redirect(users.create_login_url( - request_handler.request.uri)) + request_handler.request.uri)) return 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_class, None, - self._credentials_property_name, user=user).get() + self._credentials_class, None, + self._credentials_property_name, user=user).get() try: resp = method(request_handler, *args, **kwargs) finally: @@ -885,21 +891,26 @@ class OAuth2Decorator(object): if error: errormsg = self.request.get('error_description', error) self.response.out.write( - 'The authorization request failed: %s' % _safe_html(errormsg)) + 'The authorization request failed: %s' % + _safe_html(errormsg)) else: user = users.get_current_user() decorator._create_flow(self) - credentials = decorator.flow.step2_exchange(self.request.params) + credentials = decorator.flow.step2_exchange( + self.request.params) decorator._storage_class( - decorator._credentials_class, None, - decorator._credentials_property_name, user=user).put(credentials) - redirect_uri = _parse_state_value(str(self.request.get('state')), - user) + decorator._credentials_class, None, + decorator._credentials_property_name, + user=user).put(credentials) + 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) 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) @@ -916,7 +927,7 @@ class OAuth2Decorator(object): server during the OAuth 2.0 dance. """ return webapp.WSGIApplication([ - (self.callback_path, self.callback_handler()) + (self.callback_path, self.callback_handler()) ]) @@ -959,23 +970,25 @@ class OAuth2DecoratorFromClientSecrets(OAuth2Decorator): **kwargs: dict, Keyword arguments are passed along as kwargs to the OAuth2WebServerFlow constructor. """ - client_type, client_info = clientsecrets.loadfile(filename, cache=cache) - if client_type not in [ - clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED]: + client_type, client_info = clientsecrets.loadfile(filename, + cache=cache) + if client_type not in (clientsecrets.TYPE_WEB, + clientsecrets.TYPE_INSTALLED): 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.update({ - 'auth_uri': client_info['auth_uri'], - 'token_uri': client_info['token_uri'], - 'message': message, + 'auth_uri': client_info['auth_uri'], + 'token_uri': client_info['token_uri'], + 'message': message, }) revoke_uri = client_info.get('revoke_uri') if revoke_uri is not None: constructor_kwargs['revoke_uri'] = revoke_uri super(OAuth2DecoratorFromClientSecrets, self).__init__( - client_info['client_id'], client_info['client_secret'], - scope, **constructor_kwargs) + client_info['client_id'], client_info['client_secret'], + scope, **constructor_kwargs) if message is not None: self._message = message else: @@ -1001,4 +1014,4 @@ def oauth2decorator_from_clientsecrets(filename, scope, Returns: An OAuth2Decorator """ return OAuth2DecoratorFromClientSecrets(filename, scope, - message=message, cache=cache) + message=message, cache=cache) diff --git a/oauth2client/client.py b/oauth2client/client.py index 1d9930b..5ae9fee 100644 --- a/oauth2client/client.py +++ b/oauth2client/client.py @@ -93,12 +93,13 @@ _CLOUDSDK_CONFIG_ENV_VAR = 'CLOUDSDK_CONFIG' # The error message we show users when we can't find the Application # Default Credentials. ADC_HELP_MSG = ( - 'The Application Default Credentials are not available. They are available ' - 'if running in Google Compute Engine. Otherwise, the environment variable ' - + GOOGLE_APPLICATION_CREDENTIALS + + 'The Application Default Credentials are not available. They are ' + 'available if running in Google Compute Engine. Otherwise, the ' + 'environment variable ' + + GOOGLE_APPLICATION_CREDENTIALS + ' 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 - ' for more information.') + 'https://developers.google.com/accounts/docs/' + 'application-default-credentials for more information.') # The access token along with the seconds in which it expires. AccessTokenInfo = collections.namedtuple( @@ -132,7 +133,7 @@ class TokenRevokeError(Error): class UnknownClientSecretsFlowError(Error): - """The client secrets file called for an unknown type of OAuth 2.0 flow. """ + """The client secrets file called for an unknown type of OAuth 2.0 flow.""" class AccessTokenCredentialsError(Error): @@ -247,7 +248,7 @@ class Credentials(object): if member in d: del d[member] if (d.get('token_expiry') and - isinstance(d['token_expiry'], datetime.datetime)): + isinstance(d['token_expiry'], datetime.datetime)): d['token_expiry'] = d['token_expiry'].strftime(EXPIRY_FORMAT) # Add in information we will need later to reconsistitue this instance. d['_class'] = t.__name__ @@ -283,16 +284,19 @@ class Credentials(object): """ json_string_as_unicode = _from_bytes(s) 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'] try: module_obj = __import__(module_name) 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_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']) from_json = getattr(kls, 'from_json') return from_json(json_string_as_unicode) @@ -465,9 +469,9 @@ class OAuth2Credentials(Credentials): @util.positional(8) def __init__(self, access_token, client_id, client_secret, refresh_token, - token_expiry, token_uri, user_agent, revoke_uri=None, - id_token=None, token_response=None, scopes=None, - token_info_uri=None): + token_expiry, token_uri, user_agent, revoke_uri=None, + id_token=None, token_response=None, scopes=None, + token_info_uri=None): """Create an instance of OAuth2Credentials. This constructor is not usually called by the user, instead @@ -522,10 +526,9 @@ class OAuth2Credentials(Credentials): The modified http.request method will add authentication headers to 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, - http.request.credentials, which is the Credentials object that - authorized it. - + request. In addition the http.request method has a credentials + property, http.request.credentials, which is the Credentials object + that authorized it. Args: http: An instance of ``httplib2.Http`` or something that acts @@ -549,10 +552,11 @@ class OAuth2Credentials(Credentials): # 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): + redirections=httplib2.DEFAULT_MAX_REDIRECTS, + connection_type=None): 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) # Clone and modify the request headers to add the appropriate @@ -565,33 +569,37 @@ class OAuth2Credentials(Credentials): if self.user_agent is not None: if 'user-agent' in headers: - headers['user-agent'] = self.user_agent + ' ' + headers['user-agent'] + headers['user-agent'] = (self.user_agent + ' ' + + headers['user-agent']) else: headers['user-agent'] = self.user_agent body_stream_position = None - if all(getattr(body, stream_prop, None) for stream_prop in - ('read', 'seek', 'tell')): + if all(getattr(body, stream_prop, None) for stream_prop in + ('read', 'seek', 'tell')): body_stream_position = body.tell() - resp, content = request_orig(uri, method, body, clean_headers(headers), - redirections, connection_type) + resp, content = request_orig(uri, method, body, + clean_headers(headers), + redirections, connection_type) - # A stored token may expire between the time it is retrieved and the time - # the request is made, so we may need to try twice. + # A stored token may expire between the time it is retrieved and + # the time the request is made, so we may need to try twice. max_refresh_attempts = 2 for refresh_attempt in range(max_refresh_attempts): if resp.status not in REFRESH_STATUS_CODES: break - logger.info('Refreshing due to a %s (attempt %s/%s)', resp.status, - refresh_attempt + 1, max_refresh_attempts) + logger.info('Refreshing due to a %s (attempt %s/%s)', + resp.status, refresh_attempt + 1, + max_refresh_attempts) self._refresh(request_orig) self.apply(headers) if body_stream_position is not None: body.seek(body_stream_position) - resp, content = request_orig(uri, method, body, clean_headers(headers), - redirections, connection_type) + resp, content = request_orig(uri, method, body, + clean_headers(headers), + redirections, connection_type) return (resp, content) @@ -681,25 +689,25 @@ class OAuth2Credentials(Credentials): s = _from_bytes(s) data = json.loads(s) if (data.get('token_expiry') and - not isinstance(data['token_expiry'], datetime.datetime)): + not isinstance(data['token_expiry'], datetime.datetime)): try: data['token_expiry'] = datetime.datetime.strptime( - data['token_expiry'], EXPIRY_FORMAT) + data['token_expiry'], EXPIRY_FORMAT) except ValueError: data['token_expiry'] = None retval = cls( - data['access_token'], - data['client_id'], - data['client_secret'], - data['refresh_token'], - data['token_expiry'], - data['token_uri'], - data['user_agent'], - revoke_uri=data.get('revoke_uri', None), - id_token=data.get('id_token', None), - token_response=data.get('token_response', None), - scopes=data.get('scopes', None), - token_info_uri=data.get('token_info_uri', None)) + data['access_token'], + data['client_id'], + data['client_secret'], + data['refresh_token'], + data['token_expiry'], + data['token_uri'], + data['user_agent'], + revoke_uri=data.get('revoke_uri', None), + id_token=data.get('id_token', None), + token_response=data.get('token_response', None), + scopes=data.get('scopes', None), + token_info_uri=data.get('token_info_uri', None)) retval.invalid = data['invalid'] return retval @@ -718,7 +726,7 @@ class OAuth2Credentials(Credentials): now = datetime.datetime.utcnow() if now >= self.token_expiry: logger.info('access_token is expired. Now: %s, token_expiry: %s', - now, self.token_expiry) + now, self.token_expiry) return True return False @@ -733,7 +741,7 @@ class OAuth2Credentials(Credentials): http = httplib2.Http() self.refresh(http) return AccessTokenInfo(access_token=self.access_token, - expires_in=self._expires_in()) + expires_in=self._expires_in()) def set_store(self, store): """Set the Storage for the credential. @@ -785,17 +793,17 @@ class OAuth2Credentials(Credentials): def _generate_refresh_request_body(self): """Generate the body that will be used in the refresh request.""" body = urllib.parse.urlencode({ - 'grant_type': 'refresh_token', - 'client_id': self.client_id, - 'client_secret': self.client_secret, - 'refresh_token': self.refresh_token, + 'grant_type': 'refresh_token', + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'refresh_token': self.refresh_token, }) return body def _generate_refresh_request_headers(self): """Generate the headers that will be used in the refresh request.""" headers = { - 'content-type': 'application/x-www-form-urlencoded', + 'content-type': 'application/x-www-form-urlencoded', } if self.user_agent is not None: @@ -826,8 +834,8 @@ class OAuth2Credentials(Credentials): new_cred = self.store.locked_get() if (new_cred and not new_cred.invalid and - new_cred.access_token != self.access_token and - not new_cred.access_token_expired): + new_cred.access_token != self.access_token and + not new_cred.access_token_expired): logger.info('Updated access_token read from Storage') self._updateFromCredential(new_cred) else: @@ -851,7 +859,7 @@ class OAuth2Credentials(Credentials): logger.info('Refreshing access_token') resp, content = http_request( - self.token_uri, method='POST', body=body, headers=headers) + self.token_uri, method='POST', body=body, headers=headers) content = _from_bytes(content) if resp.status == 200: d = json.loads(content) @@ -860,7 +868,7 @@ class OAuth2Credentials(Credentials): self.refresh_token = d.get('refresh_token', self.refresh_token) if 'expires_in' in d: self.token_expiry = datetime.timedelta( - seconds=int(d['expires_in'])) + datetime.datetime.utcnow() + seconds=int(d['expires_in'])) + datetime.datetime.utcnow() else: self.token_expiry = None # On temporary refresh errors, the user does not actually have to @@ -869,8 +877,8 @@ class OAuth2Credentials(Credentials): if self.store: self.store.locked_put(self) else: - # An {'error':...} response body means the token is expired or revoked, - # so we flag the credentials as such. + # An {'error':...} response body means the token is expired or + # revoked, so we flag the credentials as such. logger.info('Failed to retrieve access token: %s', content) error_msg = 'Invalid response %s.' % resp['status'] try: @@ -955,14 +963,15 @@ class OAuth2Credentials(Credentials): """ logger.info('Refreshing scopes') 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) content = _from_bytes(content) if resp.status == 200: d = json.loads(content) self.scopes = set(util.string_to_scopes(d.get('scope', ''))) else: - error_msg = 'Invalid response %s.' % (resp.status, ) + error_msg = 'Invalid response %s.' % (resp.status,) try: d = json.loads(content) if 'error_description' in d: @@ -1012,26 +1021,26 @@ class AccessTokenCredentials(OAuth2Credentials): token can't be revoked if this is None. """ super(AccessTokenCredentials, self).__init__( - access_token, - None, - None, - None, - None, - None, - user_agent, - revoke_uri=revoke_uri) + access_token, + None, + None, + None, + None, + None, + user_agent, + revoke_uri=revoke_uri) @classmethod def from_json(cls, s): data = json.loads(_from_bytes(s)) retval = AccessTokenCredentials( - data['access_token'], - data['user_agent']) + data['access_token'], + data['user_agent']) return retval def _refresh(self, http_request): raise AccessTokenCredentialsError( - 'The access_token is expired or invalid and can\'t be refreshed.') + 'The access_token is expired or invalid and can\'t be refreshed.') def _revoke(self, http_request): """Revokes the access_token and deletes the store if available. @@ -1143,8 +1152,8 @@ class GoogleCredentials(OAuth2Credentials): """ def __init__(self, access_token, client_id, client_secret, refresh_token, - token_expiry, token_uri, user_agent, - revoke_uri=GOOGLE_REVOKE_URI): + token_expiry, token_uri, user_agent, + revoke_uri=GOOGLE_REVOKE_URI): """Create an instance of GoogleCredentials. This constructor is not usually called by the user, instead @@ -1166,8 +1175,8 @@ class GoogleCredentials(OAuth2Credentials): is None. """ super(GoogleCredentials, self).__init__( - access_token, client_id, client_secret, refresh_token, token_expiry, - token_uri, user_agent, revoke_uri=revoke_uri) + access_token, client_id, client_secret, refresh_token, + token_expiry, token_uri, user_agent, revoke_uri=revoke_uri) def create_scoped_required(self): """Whether this Credentials object is scopeless. @@ -1188,10 +1197,10 @@ class GoogleCredentials(OAuth2Credentials): def serialization_data(self): """Get the fields and values identifying the current credentials.""" return { - 'type': 'authorized_user', - 'client_id': self.client_id, - 'client_secret': self.client_secret, - 'refresh_token': self.refresh_token + 'type': 'authorized_user', + 'client_id': self.client_id, + 'client_secret': self.client_secret, + 'refresh_token': self.refresh_token } @staticmethod @@ -1247,27 +1256,29 @@ class GoogleCredentials(OAuth2Credentials): credentials_filename = _get_well_known_file() if os.path.isfile(credentials_filename): extra_help = (' (produced automatically when running' - ' "gcloud auth login" command)') + ' "gcloud auth login" command)') else: credentials_filename = None else: extra_help = (' (pointed to by ' + GOOGLE_APPLICATION_CREDENTIALS + - ' environment variable)') + ' environment variable)') if not credentials_filename: return - # If we can read the credentials from a file, we don't need to know what - # environment we are in. + # If we can read the credentials from a file, we don't need to know + # what environment we are in. SETTINGS.env_name = DEFAULT_ENV_NAME try: - return _get_application_default_credential_from_file(credentials_filename) + return _get_application_default_credential_from_file( + credentials_filename) 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 - def _get_implicit_credentials(cls): + def _get_implicit_credentials(cls): """Gets credentials implicitly from the environment. Checks environment in order of precedence: @@ -1283,9 +1294,9 @@ class GoogleCredentials(OAuth2Credentials): """ # Environ checks (in order). environ_checkers = [ - cls._implicit_credentials_from_gae, - cls._implicit_credentials_from_files, - cls._implicit_credentials_from_gce, + cls._implicit_credentials_from_gae, + cls._implicit_credentials_from_files, + cls._implicit_credentials_from_gce, ] for checker in environ_checkers: @@ -1323,16 +1334,17 @@ class GoogleCredentials(OAuth2Credentials): if credential_filename and os.path.isfile(credential_filename): try: return _get_application_default_credential_from_file( - credential_filename) + credential_filename) 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, - extra_help, - error) + extra_help, + error) else: raise ApplicationDefaultCredentialsError( - 'The parameter passed to the from_stream() ' - 'method should point to a file.') + 'The parameter passed to the from_stream() ' + 'method should point to a file.') def _save_private_file(filename, json_contents): @@ -1346,7 +1358,7 @@ def _save_private_file(filename, json_contents): file_desc = os.open(temp_filename, os.O_WRONLY | os.O_CREAT, 0o600) with os.fdopen(file_desc, 'w') as file_handle: json.dump(json_contents, file_handle, sort_keys=True, - indent=2, separators=(',', ': ')) + indent=2, separators=(',', ': ')) shutil.move(temp_filename, filename) @@ -1384,9 +1396,10 @@ def _get_environment_variable_file(): return application_default_credential_filename else: raise ApplicationDefaultCredentialsError( - 'File ' + application_default_credential_filename + ' (pointed by ' + - GOOGLE_APPLICATION_CREDENTIALS + - ' environment variable) does not exist!') + 'File ' + application_default_credential_filename + + ' (pointed by ' + + GOOGLE_APPLICATION_CREDENTIALS + + ' environment variable) does not exist!') def _get_well_known_file(): @@ -1401,16 +1414,17 @@ def _get_well_known_file(): if os.name == 'nt': try: default_config_dir = os.path.join(os.environ['APPDATA'], - _CLOUDSDK_CONFIG_DIRECTORY) + _CLOUDSDK_CONFIG_DIRECTORY) 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:') default_config_dir = os.path.join(drive, '\\', - _CLOUDSDK_CONFIG_DIRECTORY) + _CLOUDSDK_CONFIG_DIRECTORY) else: default_config_dir = os.path.join(os.path.expanduser('~'), - '.config', - _CLOUDSDK_CONFIG_DIRECTORY) + '.config', + _CLOUDSDK_CONFIG_DIRECTORY) return os.path.join(default_config_dir, WELL_KNOWN_CREDENTIALS_FILE) @@ -1429,11 +1443,11 @@ def _get_application_default_credential_from_file(filename): required_fields = set(['client_id', 'client_secret', 'refresh_token']) elif credentials_type == SERVICE_ACCOUNT: required_fields = set(['client_id', 'client_email', 'private_key_id', - 'private_key']) + 'private_key']) else: raise ApplicationDefaultCredentialsError( - "'type' field should be defined (and have one of the '" + - AUTHORIZED_USER + "' or '" + SERVICE_ACCOUNT + "' values)") + "'type' field should be defined (and have one of the '" + + AUTHORIZED_USER + "' or '" + SERVICE_ACCOUNT + "' values)") missing_fields = required_fields.difference(client_credentials.keys()) @@ -1442,25 +1456,25 @@ def _get_application_default_credential_from_file(filename): if client_credentials['type'] == AUTHORIZED_USER: return GoogleCredentials( - access_token=None, - client_id=client_credentials['client_id'], - client_secret=client_credentials['client_secret'], - refresh_token=client_credentials['refresh_token'], - token_expiry=None, - token_uri=GOOGLE_TOKEN_URI, - user_agent='Python client library') + access_token=None, + client_id=client_credentials['client_id'], + client_secret=client_credentials['client_secret'], + refresh_token=client_credentials['refresh_token'], + token_expiry=None, + token_uri=GOOGLE_TOKEN_URI, + user_agent='Python client library') else: # client_credentials['type'] == SERVICE_ACCOUNT return service_account._ServiceAccountCredentials( - service_account_id=client_credentials['client_id'], - service_account_email=client_credentials['client_email'], - private_key_id=client_credentials['private_key_id'], - private_key_pkcs8_text=client_credentials['private_key'], - scopes=[]) + service_account_id=client_credentials['client_id'], + service_account_email=client_credentials['client_email'], + private_key_id=client_credentials['private_key_id'], + private_key_pkcs8_text=client_credentials['private_key'], + scopes=[]) def _raise_exception_for_missing_fields(missing_fields): raise ApplicationDefaultCredentialsError( - 'The following field(s) must be defined: ' + ', '.join(missing_fields)) + 'The following field(s) must be defined: ' + ', '.join(missing_fields)) def _raise_exception_for_reading_json(credential_file, @@ -1496,9 +1510,9 @@ class AssertionCredentials(GoogleCredentials): @util.positional(2) def __init__(self, assertion_type, user_agent=None, - token_uri=GOOGLE_TOKEN_URI, - revoke_uri=GOOGLE_REVOKE_URI, - **unused_kwargs): + token_uri=GOOGLE_TOKEN_URI, + revoke_uri=GOOGLE_REVOKE_URI, + **unused_kwargs): """Constructor for AssertionFlowCredentials. Args: @@ -1512,22 +1526,22 @@ class AssertionCredentials(GoogleCredentials): revoke_uri: string, URI for revoke endpoint. """ super(AssertionCredentials, self).__init__( - None, - None, - None, - None, - None, - token_uri, - user_agent, - revoke_uri=revoke_uri) + None, + None, + None, + None, + None, + token_uri, + user_agent, + revoke_uri=revoke_uri) self.assertion_type = assertion_type def _generate_refresh_request_body(self): assertion = self._generate_assertion() body = urllib.parse.urlencode({ - 'assertion': assertion, - 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', + 'assertion': assertion, + 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', }) return body @@ -1574,14 +1588,14 @@ class SignedJwtAssertionCredentials(AssertionCredentials): @util.positional(4) def __init__(self, - service_account_name, - private_key, - scope, - private_key_password='notasecret', - user_agent=None, - token_uri=GOOGLE_TOKEN_URI, - revoke_uri=GOOGLE_REVOKE_URI, - **kwargs): + service_account_name, + private_key, + scope, + private_key_password='notasecret', + user_agent=None, + token_uri=GOOGLE_TOKEN_URI, + revoke_uri=GOOGLE_REVOKE_URI, + **kwargs): """Constructor for SignedJwtAssertionCredentials. Args: @@ -1606,10 +1620,10 @@ class SignedJwtAssertionCredentials(AssertionCredentials): """ _RequireCryptoOrDie() super(SignedJwtAssertionCredentials, 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.scope = util.scopes_to_string(scope) @@ -1625,13 +1639,13 @@ class SignedJwtAssertionCredentials(AssertionCredentials): def from_json(cls, s): data = json.loads(_from_bytes(s)) retval = SignedJwtAssertionCredentials( - data['service_account_name'], - base64.b64decode(data['private_key']), - data['scope'], - private_key_password=data['private_key_password'], - user_agent=data['user_agent'], - token_uri=data['token_uri'], - **data['kwargs'] + data['service_account_name'], + base64.b64decode(data['private_key']), + data['scope'], + private_key_password=data['private_key_password'], + user_agent=data['user_agent'], + token_uri=data['token_uri'], + **data['kwargs'] ) retval.invalid = data['invalid'] retval.access_token = data['access_token'] @@ -1641,18 +1655,18 @@ class SignedJwtAssertionCredentials(AssertionCredentials): """Generate the assertion that will be used in the request.""" now = int(time.time()) payload = { - 'aud': self.token_uri, - 'scope': self.scope, - 'iat': now, - 'exp': now + SignedJwtAssertionCredentials.MAX_TOKEN_LIFETIME_SECS, - 'iss': self.service_account_name + 'aud': self.token_uri, + 'scope': self.scope, + 'iat': now, + 'exp': now + SignedJwtAssertionCredentials.MAX_TOKEN_LIFETIME_SECS, + 'iss': self.service_account_name } payload.update(self.kwargs) logger.debug(str(payload)) private_key = base64.b64decode(self.private_key) return crypt.make_signed_jwt(crypt.Signer.from_string( - private_key, self.private_key_password), payload) + private_key, self.private_key_password), payload) # Only used in verify_id_token(), which is always calling to the same URI # for the certs. @@ -1712,7 +1726,7 @@ def _extract_id_token(id_token): if len(segments) != 3: raise VerifyJwtTokenError( - 'Wrong number of segments in token: %s' % id_token) + 'Wrong number of segments in token: %s' % id_token) return json.loads(_from_bytes(_urlsafe_b64decode(segments[1]))) @@ -1786,10 +1800,11 @@ def credentials_from_code(client_id, client_secret, scope, code, access token """ flow = OAuth2WebServerFlow(client_id, client_secret, scope, - redirect_uri=redirect_uri, user_agent=user_agent, - auth_uri=auth_uri, token_uri=token_uri, - revoke_uri=revoke_uri, device_uri=device_uri, - token_info_uri=token_info_uri) + redirect_uri=redirect_uri, + user_agent=user_agent, auth_uri=auth_uri, + token_uri=token_uri, revoke_uri=revoke_uri, + device_uri=device_uri, + token_info_uri=token_info_uri) credentials = flow.step2_exchange(code, http=http) return credentials @@ -1836,16 +1851,16 @@ def credentials_from_clientsecrets_and_code(filename, scope, code, clientsecrets.InvalidClientSecretsError: if the clientsecrets file is invalid. """ - flow = flow_from_clientsecrets(filename, scope, message=message, cache=cache, - redirect_uri=redirect_uri, - device_uri=device_uri) + flow = flow_from_clientsecrets(filename, scope, message=message, + cache=cache, redirect_uri=redirect_uri, + device_uri=device_uri) credentials = flow.step2_exchange(code, http=http) return credentials class DeviceFlowInfo(collections.namedtuple('DeviceFlowInfo', ( - 'device_code', 'user_code', 'interval', 'verification_url', - 'user_code_expiry'))): + 'device_code', 'user_code', 'interval', 'verification_url', + 'user_code_expiry'))): """Intermediate information the OAuth2 for devices flow.""" @classmethod @@ -1858,26 +1873,26 @@ class DeviceFlowInfo(collections.namedtuple('DeviceFlowInfo', ( """ # device_code, user_code, and verification_url are required. kwargs = { - 'device_code': response['device_code'], - 'user_code': response['user_code'], + 'device_code': response['device_code'], + 'user_code': response['user_code'], } # The response may list the verification address as either # verification_url or verification_uri, so we check for both. verification_url = response.get( - 'verification_url', response.get('verification_uri')) + 'verification_url', response.get('verification_uri')) if verification_url is None: raise OAuth2DeviceCodeError( - 'No verification_url provided in server response') + 'No verification_url provided in server response') kwargs['verification_url'] = verification_url # expires_in and interval are optional. kwargs.update({ - 'interval': response.get('interval'), - 'user_code_expiry': None, + 'interval': response.get('interval'), + 'user_code_expiry': None, }) if 'expires_in' in response: - kwargs['user_code_expiry'] = datetime.datetime.now() + datetime.timedelta( - seconds=int(response['expires_in'])) - + kwargs['user_code_expiry'] = ( + datetime.datetime.now() + + datetime.timedelta(seconds=int(response['expires_in']))) return cls(**kwargs) @@ -1889,18 +1904,18 @@ class OAuth2WebServerFlow(Flow): @util.positional(4) def __init__(self, client_id, - client_secret=None, - scope=None, - redirect_uri=None, - user_agent=None, - auth_uri=GOOGLE_AUTH_URI, - token_uri=GOOGLE_TOKEN_URI, - revoke_uri=GOOGLE_REVOKE_URI, - login_hint=None, - device_uri=GOOGLE_DEVICE_URI, - token_info_uri=GOOGLE_TOKEN_INFO_URI, - authorization_header=None, - **kwargs): + client_secret=None, + scope=None, + redirect_uri=None, + user_agent=None, + auth_uri=GOOGLE_AUTH_URI, + token_uri=GOOGLE_TOKEN_URI, + revoke_uri=GOOGLE_REVOKE_URI, + login_hint=None, + device_uri=GOOGLE_DEVICE_URI, + token_info_uri=GOOGLE_TOKEN_INFO_URI, + authorization_header=None, + **kwargs): """Constructor for OAuth2WebServerFlow. The kwargs argument is used to set extra query parameters on the @@ -1915,7 +1930,8 @@ class OAuth2WebServerFlow(Flow): redirect_uri: string, Either the string 'urn:ietf:wg:oauth:2.0:oob' for a non-web-based application, or a URI that 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 defaults to Google's endpoints but any OAuth 2.0 provider can be used. @@ -1956,8 +1972,8 @@ class OAuth2WebServerFlow(Flow): self.token_info_uri = token_info_uri self.authorization_header = authorization_header self.params = { - 'access_type': 'offline', - 'response_type': 'code', + 'access_type': 'offline', + 'response_type': 'code', } self.params.update(kwargs) @@ -1981,18 +1997,19 @@ class OAuth2WebServerFlow(Flow): """ if redirect_uri is not None: logger.warning(( - 'The redirect_uri parameter for ' - 'OAuth2WebServerFlow.step1_get_authorize_url is deprecated. Please ' - 'move to passing the redirect_uri in via the constructor.')) + 'The redirect_uri parameter for ' + 'OAuth2WebServerFlow.step1_get_authorize_url is deprecated. ' + 'Please move to passing the redirect_uri in via the ' + 'constructor.')) self.redirect_uri = redirect_uri if self.redirect_uri is None: raise ValueError('The value of redirect_uri must not be None.') query_params = { - 'client_id': self.client_id, - 'redirect_uri': self.redirect_uri, - 'scope': self.scope, + 'client_id': self.client_id, + 'redirect_uri': self.redirect_uri, + 'scope': self.scope, } if state is not None: query_params['state'] = state @@ -2013,11 +2030,11 @@ class OAuth2WebServerFlow(Flow): raise ValueError('The value of device_uri must not be None.') body = urllib.parse.urlencode({ - 'client_id': self.client_id, - 'scope': self.scope, + 'client_id': self.client_id, + 'scope': self.scope, }) headers = { - 'content-type': 'application/x-www-form-urlencoded', + 'content-type': 'application/x-www-form-urlencoded', } if self.user_agent is not None: @@ -2027,15 +2044,15 @@ class OAuth2WebServerFlow(Flow): http = httplib2.Http() resp, content = http.request(self.device_uri, method='POST', body=body, - headers=headers) + headers=headers) content = _from_bytes(content) if resp.status == 200: try: flow_info = json.loads(content) except ValueError as e: raise OAuth2DeviceCodeError( - 'Could not parse server response as JSON: "%s", error: "%s"' % ( - content, e)) + 'Could not parse server response as JSON: "%s", ' + 'error: "%s"' % (content, e)) return DeviceFlowInfo.FromResponse(flow_info) else: error_msg = 'Invalid response %s.' % resp.status @@ -2044,12 +2061,13 @@ class OAuth2WebServerFlow(Flow): if 'error' in d: error_msg += ' Error: %s' % d['error'] 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 raise OAuth2DeviceCodeError(error_msg) @util.positional(2) - def step2_exchange(self, code=None, http=None, device_flow_info=None): + def step2_exchange(self, code=None, http=None, device_flow_info=None): """Exchanges a code for OAuth2Credentials. Args: @@ -2081,13 +2099,13 @@ class OAuth2WebServerFlow(Flow): elif not isinstance(code, six.string_types): if 'code' not in code: raise FlowExchangeError(code.get( - 'error', 'No code was supplied in the query parameters.')) + 'error', 'No code was supplied in the query parameters.')) code = code['code'] post_data = { - 'client_id': self.client_id, - 'code': code, - 'scope': self.scope, + 'client_id': self.client_id, + 'code': code, + 'scope': self.scope, } if self.client_secret is not None: post_data['client_secret'] = self.client_secret @@ -2098,7 +2116,7 @@ class OAuth2WebServerFlow(Flow): post_data['redirect_uri'] = self.redirect_uri body = urllib.parse.urlencode(post_data) headers = { - 'content-type': 'application/x-www-form-urlencoded', + 'content-type': 'application/x-www-form-urlencoded', } if self.authorization_header is not None: headers['Authorization'] = self.authorization_header @@ -2109,38 +2127,38 @@ class OAuth2WebServerFlow(Flow): http = httplib2.Http() resp, content = http.request(self.token_uri, method='POST', body=body, - headers=headers) + headers=headers) d = _parse_exchange_token_response(content) if resp.status == 200 and 'access_token' in d: access_token = d['access_token'] refresh_token = d.get('refresh_token', None) if not refresh_token: logger.info( - 'Received token response with no refresh_token. Consider ' - "reauthenticating with approval_prompt='force'.") + 'Received token response with no refresh_token. Consider ' + "reauthenticating with approval_prompt='force'.") token_expiry = None if 'expires_in' in d: - token_expiry = datetime.datetime.utcnow() + datetime.timedelta( - seconds=int(d['expires_in'])) + token_expiry = ( + datetime.datetime.utcnow() + + datetime.timedelta(seconds=int(d['expires_in']))) extracted_id_token = None if 'id_token' in d: extracted_id_token = _extract_id_token(d['id_token']) logger.info('Successfully retrieved access token') - return OAuth2Credentials(access_token, self.client_id, - self.client_secret, refresh_token, token_expiry, - self.token_uri, self.user_agent, - revoke_uri=self.revoke_uri, - id_token=extracted_id_token, - token_response=d, - scopes=self.scope, - token_info_uri=self.token_info_uri) + return OAuth2Credentials( + access_token, self.client_id, self.client_secret, + refresh_token, token_expiry, self.token_uri, self.user_agent, + revoke_uri=self.revoke_uri, id_token=extracted_id_token, + token_response=d, scopes=self.scope, + token_info_uri=self.token_info_uri) else: logger.info('Failed to retrieve access token: %s', content) if 'error' in d: # 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: error_msg = 'Invalid response: %s.' % str(resp.status) raise FlowExchangeError(error_msg) @@ -2187,13 +2205,15 @@ def flow_from_clientsecrets(filename, scope, redirect_uri=None, invalid. """ try: - client_type, client_info = clientsecrets.loadfile(filename, cache=cache) - if client_type in (clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED): + client_type, client_info = clientsecrets.loadfile(filename, + cache=cache) + if client_type in (clientsecrets.TYPE_WEB, + clientsecrets.TYPE_INSTALLED): constructor_kwargs = { - 'redirect_uri': redirect_uri, - 'auth_uri': client_info['auth_uri'], - 'token_uri': client_info['token_uri'], - 'login_hint': login_hint, + 'redirect_uri': redirect_uri, + 'auth_uri': client_info['auth_uri'], + 'token_uri': client_info['token_uri'], + 'login_hint': login_hint, } revoke_uri = client_info.get('revoke_uri') if revoke_uri is not None: @@ -2201,8 +2221,8 @@ def flow_from_clientsecrets(filename, scope, redirect_uri=None, if device_uri is not None: constructor_kwargs['device_uri'] = device_uri return OAuth2WebServerFlow( - client_info['client_id'], client_info['client_secret'], - scope, **constructor_kwargs) + client_info['client_id'], client_info['client_secret'], + scope, **constructor_kwargs) except clientsecrets.InvalidClientSecretsError: if message: @@ -2211,4 +2231,4 @@ def flow_from_clientsecrets(filename, scope, redirect_uri=None, raise else: raise UnknownClientSecretsFlowError( - 'This OAuth 2.0 flow is unsupported: %r' % client_type) + 'This OAuth 2.0 flow is unsupported: %r' % client_type) diff --git a/oauth2client/clientsecrets.py b/oauth2client/clientsecrets.py index cf7472f..c8c21e3 100644 --- a/oauth2client/clientsecrets.py +++ b/oauth2client/clientsecrets.py @@ -70,30 +70,31 @@ class InvalidClientSecretsError(Error): def _validate_clientsecrets(obj): _INVALID_FILE_FORMAT_MSG = ( - 'Invalid file format. See ' - 'https://developers.google.com/api-client-library/' - 'python/guide/aaa_client_secrets') + 'Invalid file format. See ' + 'https://developers.google.com/api-client-library/' + 'python/guide/aaa_client_secrets') if obj is None: raise InvalidClientSecretsError(_INVALID_FILE_FORMAT_MSG) if len(obj) != 1: raise InvalidClientSecretsError( - _INVALID_FILE_FORMAT_MSG + ' ' - 'Expected a JSON object with a single property for a "web" or ' - '"installed" application') + _INVALID_FILE_FORMAT_MSG + ' ' + 'Expected a JSON object with a single property for a "web" or ' + '"installed" application') client_type = tuple(obj)[0] 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] for prop_name in VALID_CLIENT[client_type]['required']: if prop_name not in client_info: raise InvalidClientSecretsError( - 'Missing property "%s" in a client type of "%s".' % (prop_name, - client_type)) + 'Missing property "%s" in a client type of "%s".' % + (prop_name, client_type)) for prop_name in VALID_CLIENT[client_type]['string']: if client_info[prop_name].startswith('[['): raise InvalidClientSecretsError( - 'Property "%s" is not configured.' % prop_name) + 'Property "%s" is not configured.' % prop_name) return client_type, client_info diff --git a/oauth2client/crypt.py b/oauth2client/crypt.py index 6d22472..de62e06 100644 --- a/oauth2client/crypt.py +++ b/oauth2client/crypt.py @@ -45,11 +45,9 @@ except ImportError: OpenSSLVerifier = None OpenSSLSigner = None - def pkcs12_key_as_pem(*args, **kwargs): raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.') - try: from oauth2client._pycrypto_crypt import PyCryptoVerifier from oauth2client._pycrypto_crypt import PyCryptoSigner @@ -66,7 +64,7 @@ elif PyCryptoSigner: Verifier = PyCryptoVerifier else: raise ImportError('No encryption library found. Please install either ' - 'PyOpenSSL, or PyCrypto 2.6 or later') + 'PyOpenSSL, or PyCrypto 2.6 or later') def make_signed_jwt(signer, payload): @@ -157,10 +155,10 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): if now < earliest: raise AppIdentityError('Token used too early, %d < %d: %s' % - (now, earliest, json_body)) + (now, earliest, json_body)) if now > latest: raise AppIdentityError('Token used too late, %d > %d: %s' % - (now, latest, json_body)) + (now, latest, json_body)) # Check audience. if audience is not None: @@ -169,6 +167,6 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): raise AppIdentityError('No aud field in token: %s' % json_body) if aud != audience: raise AppIdentityError('Wrong recipient, %s != %s: %s' % - (aud, audience, json_body)) + (aud, audience, json_body)) return parsed diff --git a/oauth2client/devshell.py b/oauth2client/devshell.py index 1ebf38c..4e9218f 100644 --- a/oauth2client/devshell.py +++ b/oauth2client/devshell.py @@ -35,8 +35,9 @@ class CommunicationError(Error): class NoDevshellServer(Error): """Error when no Developer Shell server can be contacted.""" -# The request for credential information to the Developer Shell client socket is -# always an empty PBLite-formatted JSON object, so just define it as a constant. +# The request for credential information to the Developer Shell client socket +# is always an empty PBLite-formatted JSON object, so just define it as a +# constant. CREDENTIAL_INFO_REQUEST_JSON = '[]' @@ -44,7 +45,9 @@ class CredentialInfoResponse(object): """Credential information response from Developer Shell server. 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 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. @@ -103,13 +106,13 @@ class DevshellCredentials(client.GoogleCredentials): def __init__(self, user_agent=None): super(DevshellCredentials, self).__init__( - None, # access_token, initialized below - None, # client_id - None, # client_secret - None, # refresh_token - None, # token_expiry - None, # token_uri - user_agent) + None, # access_token, initialized below + None, # client_id + None, # client_secret + None, # refresh_token + None, # token_expiry + None, # token_uri + user_agent) self._refresh(None) def _refresh(self, http_request): @@ -127,9 +130,9 @@ class DevshellCredentials(client.GoogleCredentials): @classmethod def from_json(cls, json_data): raise NotImplementedError( - 'Cannot load Developer Shell credentials from JSON.') + 'Cannot load Developer Shell credentials from JSON.') @property def serialization_data(self): raise NotImplementedError( - 'Cannot serialize Developer Shell credentials.') + 'Cannot serialize Developer Shell credentials.') diff --git a/oauth2client/django_orm.py b/oauth2client/django_orm.py index 1df9b84..d119f04 100644 --- a/oauth2client/django_orm.py +++ b/oauth2client/django_orm.py @@ -93,7 +93,8 @@ class Storage(BaseStorage): Args: model: db.Model, model class 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 CredentialsProperty """ @@ -124,12 +125,14 @@ class Storage(BaseStorage): Args: credentials: Credentials, the credentials to store. 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} 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: entity = self.model_class(**args) diff --git a/oauth2client/file.py b/oauth2client/file.py index 83add1c..d0dd174 100644 --- a/oauth2client/file.py +++ b/oauth2client/file.py @@ -42,7 +42,7 @@ class Storage(BaseStorage): def _validate_file(self): if os.path.islink(self._filename): raise CredentialsFileSymbolicLinkError( - 'File: %s is a symbolic link.' % self._filename) + 'File: %s is a symbolic link.' % self._filename) def acquire_lock(self): """Acquires any lock necessary to access this Storage. diff --git a/oauth2client/flask_util.py b/oauth2client/flask_util.py index 85fc0b0..85baa23 100644 --- a/oauth2client/flask_util.py +++ b/oauth2client/flask_util.py @@ -46,8 +46,8 @@ apiui/credential>`__. Usage ===== -Once configured, you can use the :meth:`UserOAuth2.required` decorator to ensure -that credentials are available within a view. +Once configured, you can use the :meth:`UserOAuth2.required` decorator to +ensure that credentials are available within a view. .. code-block:: python :emphasize-lines: 3,7,10 @@ -190,7 +190,7 @@ from oauth2client import util __author__ = 'jonwayne@google.com (Jon Wayne Parrott)' -DEFAULT_SCOPES = ('email', ) +DEFAULT_SCOPES = ('email',) class UserOAuth2(object): @@ -291,8 +291,9 @@ class UserOAuth2(object): raise ValueError( 'OAuth2 configuration could not be found. Either specify the ' 'client_secrets_file or client_id and client_secret or set the' - 'app configuration variables GOOGLE_OAUTH2_CLIENT_SECRETS_FILE ' - 'or GOOGLE_OAUTH2_CLIENT_ID and GOOGLE_OAUTH2_CLIENT_SECRET.') + 'app configuration variables ' + 'GOOGLE_OAUTH2_CLIENT_SECRETS_FILE or ' + 'GOOGLE_OAUTH2_CLIENT_ID and GOOGLE_OAUTH2_CLIENT_SECRET.') def _load_client_secrets(self, filename): """Loads client secrets from the given filename.""" @@ -392,7 +393,8 @@ class UserOAuth2(object): credentials = flow.step2_exchange(code) except FlowExchangeError as 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. self.storage.put(credentials) @@ -420,9 +422,9 @@ class UserOAuth2(object): def email(self): """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 - should not be used as unique identifier as the user can change their - email. If you need a unique identifier, use user_id. + The email address is provided by the current credentials' id_token. + This should not be used as unique identifier as the user can change + their email. If you need a unique identifier, use user_id. """ if not self.credentials: return None @@ -451,8 +453,9 @@ class UserOAuth2(object): def authorize_url(self, return_url, **kwargs): """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. - Once complete, the user will be redirected to the specified return URL. + When the user is directed to the URL, the authorization flow will + begin. Once complete, the user will be redirected to the specified + return URL. Any kwargs are passed into the flow constructor. """ diff --git a/oauth2client/gce.py b/oauth2client/gce.py index 61ad296..4b0b7ef 100644 --- a/oauth2client/gce.py +++ b/oauth2client/gce.py @@ -44,9 +44,9 @@ class AppAssertionCredentials(AssertionCredentials): used for the purpose of accessing data stored under an account assigned to the Compute Engine instance itself. - This credential does not require a flow to instantiate because it represents - a two legged flow, and therefore has all of the required information to - generate and refresh its own access tokens. + This credential does not require a flow to instantiate because it + represents a two legged flow, and therefore has all of the required + information to generate and refresh its own access tokens. """ @util.positional(2) @@ -60,7 +60,8 @@ class AppAssertionCredentials(AssertionCredentials): self.scope = util.scopes_to_string(scope) 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) @classmethod @@ -74,9 +75,9 @@ class AppAssertionCredentials(AssertionCredentials): Skip all the storage hoops and just refresh using the API. Args: - http_request: callable, a callable that matches the method signature - of httplib2.Http.request, used to make the refresh - request. + http_request: callable, a callable that matches the method + signature of httplib2.Http.request, used to make + the refresh request. Raises: AccessTokenRefreshError: When the refresh fails. @@ -94,13 +95,13 @@ class AppAssertionCredentials(AssertionCredentials): else: if response.status == 404: content += (' This can occur if a VM was created' - ' with no service account or scopes.') + ' with no service account or scopes.') raise AccessTokenRefreshError(content) @property - def serialization_data(self): + def serialization_data(self): raise NotImplementedError( - 'Cannot serialize credentials for GCE service accounts.') + 'Cannot serialize credentials for GCE service accounts.') def create_scoped_required(self): return not self.scope diff --git a/oauth2client/keyring_storage.py b/oauth2client/keyring_storage.py index 11cdc36..0a4c285 100644 --- a/oauth2client/keyring_storage.py +++ b/oauth2client/keyring_storage.py @@ -103,7 +103,7 @@ class Storage(BaseStorage): credentials: Credentials, the credentials to store. """ keyring.set_password(self._service_name, self._user_name, - credentials.to_json()) + credentials.to_json()) def locked_delete(self): """Delete Credentials file. diff --git a/oauth2client/locked_file.py b/oauth2client/locked_file.py index 3c9eaf9..ba9cdb9 100644 --- a/oauth2client/locked_file.py +++ b/oauth2client/locked_file.py @@ -57,7 +57,7 @@ class AlreadyLockedException(Exception): def validate_file(filename): if os.path.islink(filename): raise CredentialsFileSymbolicLinkError( - 'File: %s is a symbolic link.' % filename) + 'File: %s is a symbolic link.' % filename) class _Opener(object): @@ -123,7 +123,7 @@ class _PosixOpener(_Opener): """ if self._locked: raise AlreadyLockedException('File %s is already locked' % - self._filename) + self._filename) self._locked = False validate_file(self._filename) @@ -140,7 +140,7 @@ class _PosixOpener(_Opener): while True: try: self._lock_fd = os.open(lock_filename, - os.O_CREAT | os.O_EXCL | os.O_RDWR) + os.O_CREAT | os.O_EXCL | os.O_RDWR) self._locked = True break @@ -149,7 +149,7 @@ class _PosixOpener(_Opener): raise if (time.time() - start_time) >= timeout: logger.warn('Could not acquire lock %s in %s seconds', - lock_filename, timeout) + lock_filename, timeout) # Close the file and open in fallback_mode. if self._fh: self._fh.close() @@ -176,7 +176,6 @@ class _PosixOpener(_Opener): try: import fcntl - class _FcntlOpener(_Opener): """Open, lock, and unlock a file using fcntl.lockf.""" @@ -190,18 +189,20 @@ try: Raises: AlreadyLockedException: if the lock is already acquired. IOError: if the open fails. - CredentialsFileSymbolicLinkError if the file is a symbolic link. + CredentialsFileSymbolicLinkError: if the file is a symbolic + link. """ if self._locked: raise AlreadyLockedException('File %s is already locked' % - self._filename) + self._filename) start_time = time.time() validate_file(self._filename) try: self._fh = open(self._filename, self._mode) 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): self._fh = open(self._filename, self._fallback_mode) return @@ -221,7 +222,7 @@ try: # We could not acquire the lock. Try again. if (time.time() - start_time) >= timeout: logger.warn('Could not lock %s in %s seconds', - self._filename, timeout) + self._filename, timeout) if self._fh: self._fh.close() self._fh = open(self._filename, self._fallback_mode) @@ -244,7 +245,6 @@ try: import win32con import win32file - class _Win32Opener(_Opener): """Open, lock, and unlock a file using windows primitives.""" @@ -271,14 +271,15 @@ try: """ if self._locked: raise AlreadyLockedException('File %s is already locked' % - self._filename) + self._filename) start_time = time.time() validate_file(self._filename) try: self._fh = open(self._filename, self._mode) 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: self._fh = open(self._filename, self._fallback_mode) return @@ -288,24 +289,25 @@ try: try: hfile = win32file._get_osfhandle(self._fh.fileno()) win32file.LockFileEx( - hfile, - (win32con.LOCKFILE_FAIL_IMMEDIATELY | - win32con.LOCKFILE_EXCLUSIVE_LOCK), 0, -0x10000, - pywintypes.OVERLAPPED()) + hfile, + (win32con.LOCKFILE_FAIL_IMMEDIATELY | + win32con.LOCKFILE_EXCLUSIVE_LOCK), 0, -0x10000, + pywintypes.OVERLAPPED()) self._locked = True return except pywintypes.error as e: if timeout == 0: 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: raise # We could not acquire the lock. Try again. if (time.time() - start_time) >= timeout: logger.warn('Could not lock %s in %s seconds' % ( - self._filename, timeout)) + self._filename, timeout)) if self._fh: self._fh.close() self._fh = open(self._filename, self._fallback_mode) @@ -317,12 +319,13 @@ try: if self._locked: try: 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: if e[0] != _Win32Opener.FILE_ALREADY_UNLOCKED_ERROR: raise self._locked = False - if self._fh: + if self._fh: self._fh.close() except ImportError: _Win32Opener = None diff --git a/oauth2client/multistore_file.py b/oauth2client/multistore_file.py index b2458d6..f5a8593 100644 --- a/oauth2client/multistore_file.py +++ b/oauth2client/multistore_file.py @@ -91,14 +91,14 @@ def get_credential_storage(filename, client_id, user_agent, scope, """ # Recreate the legacy key with these specific parameters key = {'clientId': client_id, 'userAgent': user_agent, - 'scope': util.scopes_to_string(scope)} + 'scope': util.scopes_to_string(scope)} return get_credential_storage_custom_key( filename, key, warn_on_readonly=warn_on_readonly) @util.positional(2) -def get_credential_storage_custom_string_key( - filename, key_string, warn_on_readonly=True): +def get_credential_storage_custom_string_key(filename, key_string, + warn_on_readonly=True): """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 @@ -120,8 +120,8 @@ def get_credential_storage_custom_string_key( @util.positional(2) -def get_credential_storage_custom_key( - filename, key_dict, warn_on_readonly=True): +def get_credential_storage_custom_key(filename, key_dict, + warn_on_readonly=True): """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 @@ -179,7 +179,7 @@ def _get_multistore(filename, warn_on_readonly=True): _multistores_lock.acquire() try: multistore = _multistores.setdefault( - filename, _MultiStore(filename, warn_on_readonly=warn_on_readonly)) + filename, _MultiStore(filename, warn_on_readonly=warn_on_readonly)) finally: _multistores_lock.release() return multistore @@ -211,7 +211,7 @@ class _MultiStore(object): self._data = None 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): self._multistore = multistore @@ -285,19 +285,20 @@ class _MultiStore(object): self._file.open_and_lock() except IOError as e: if e.errno == errno.ENOSYS: - logger.warn('File system does not support locking the credentials ' - 'file.') + logger.warn('File system does not support locking the ' + 'credentials file.') elif e.errno == errno.ENOLCK: logger.warn('File system is out of resources for writing the ' - 'credentials file (is your disk full?).') + 'credentials file (is your disk full?).') else: raise if not self._file.is_locked(): self._read_only = True if self._warn_on_readonly: - logger.warn('The credentials file (%s) is not writable. Opening in ' - 'read-only mode. Any refreshed credentials will only be ' - 'valid for this run.', self._file.filename()) + logger.warn('The credentials file (%s) is not writable. ' + 'Opening in read-only mode. Any refreshed ' + 'credentials will only be ' + 'valid for this run.', self._file.filename()) if os.path.getsize(self._file.filename()) == 0: logger.debug('Initializing empty multistore file') # The multistore is empty so write out an empty file. @@ -340,7 +341,8 @@ class _MultiStore(object): if self._read_only: return 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() def _refresh_data_cache(self): @@ -357,7 +359,7 @@ class _MultiStore(object): raw_data = self._locked_json_read() except Exception: logger.warn('Credential data store could not be loaded. ' - 'Will ignore and overwrite.') + 'Will ignore and overwrite.') return version = 0 @@ -365,11 +367,11 @@ class _MultiStore(object): version = raw_data['file_version'] except Exception: logger.warn('Missing version for credential data store. It may be ' - 'corrupt or an old version. Overwriting.') + 'corrupt or an old version. Overwriting.') if version > 1: raise NewerCredentialStoreError( - 'Credential file has file_version of %d. ' - 'Only file_version of 1 is supported.' % version) + 'Credential file has file_version of %d. ' + 'Only file_version of 1 is supported.' % version) credentials = [] try: @@ -379,11 +381,12 @@ class _MultiStore(object): for cred_entry in credentials: try: - (key, credential) = self._decode_credential_from_json(cred_entry) + key, credential = self._decode_credential_from_json(cred_entry) self._data[key] = credential except: # 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): """Load a credential from our JSON serialization. @@ -398,7 +401,8 @@ class _MultiStore(object): raw_key = cred_entry['key'] key = util.dict_to_tuple_key(raw_key) 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) def _write(self): diff --git a/oauth2client/old_run.py b/oauth2client/old_run.py index 1517eb7..70065e4 100644 --- a/oauth2client/old_run.py +++ b/oauth2client/old_run.py @@ -72,7 +72,8 @@ def run(flow, storage, http=None): of values. ``--[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 calling ``run()``. @@ -87,8 +88,8 @@ def run(flow, storage, http=None): Credentials, the obtained credential. """ logging.warning('This function, oauth2client.tools.run(), and the use of ' - 'the gflags library are deprecated and will be removed in a future ' - 'version of the library.') + 'the gflags library are deprecated and will be removed in ' + 'a future version of the library.') if FLAGS.auth_local_webserver: success = False port_number = 0 @@ -96,7 +97,7 @@ def run(flow, storage, http=None): port_number = port try: httpd = ClientRedirectServer((FLAGS.auth_host_name, port), - ClientRedirectHandler) + ClientRedirectHandler) except socket.error as e: pass else: @@ -104,13 +105,14 @@ def run(flow, storage, http=None): break FLAGS.auth_local_webserver = success if not success: - print('Failed to start a local webserver listening on either port 8080') - print('or port 9090. Please check your firewall settings and locally') - print('running programs that may be blocking or using those ports.') - print() - print('Falling back to --noauth_local_webserver and continuing with') - print('authorization.') - print() + print('Failed to start a local webserver listening on ' + 'either port 8080') + print('or port 9090. Please check your firewall settings and locally') + print('running programs that may be blocking or using those ports.') + print() + print('Falling back to --noauth_local_webserver and continuing with') + print('authorization.') + print() if FLAGS.auth_local_webserver: oauth_callback = 'http://%s:%s/' % (FLAGS.auth_host_name, port_number) @@ -144,7 +146,8 @@ def run(flow, storage, http=None): if 'code' in httpd.query_params: code = httpd.query_params['code'] 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.') else: code = input('Enter verification code: ').strip() diff --git a/oauth2client/service_account.py b/oauth2client/service_account.py index 321ebf0..8d3dc65 100644 --- a/oauth2client/service_account.py +++ b/oauth2client/service_account.py @@ -38,13 +38,14 @@ class _ServiceAccountCredentials(AssertionCredentials): MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds - def __init__(self, service_account_id, service_account_email, private_key_id, - private_key_pkcs8_text, scopes, user_agent=None, - token_uri=GOOGLE_TOKEN_URI, revoke_uri=GOOGLE_REVOKE_URI, - **kwargs): + def __init__(self, service_account_id, service_account_email, + private_key_id, private_key_pkcs8_text, scopes, + user_agent=None, token_uri=GOOGLE_TOKEN_URI, + revoke_uri=GOOGLE_REVOKE_URI, **kwargs): 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_email = service_account_email @@ -61,18 +62,18 @@ class _ServiceAccountCredentials(AssertionCredentials): """Generate the assertion that will be used in the request.""" header = { - 'alg': 'RS256', - 'typ': 'JWT', - 'kid': self._private_key_id + 'alg': 'RS256', + 'typ': 'JWT', + 'kid': self._private_key_id } now = int(time.time()) payload = { - 'aud': self._token_uri, - 'scope': self._scopes, - 'iat': now, - 'exp': now + _ServiceAccountCredentials.MAX_TOKEN_LIFETIME_SECS, - 'iss': self._service_account_email + 'aud': self._token_uri, + 'scope': self._scopes, + 'iat': now, + 'exp': now + _ServiceAccountCredentials.MAX_TOKEN_LIFETIME_SECS, + 'iss': self._service_account_email } payload.update(self._kwargs) @@ -81,7 +82,8 @@ class _ServiceAccountCredentials(AssertionCredentials): assertion_input = first_segment + b'.' + second_segment # 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'=') return assertion_input + b'.' + signature @@ -90,7 +92,7 @@ class _ServiceAccountCredentials(AssertionCredentials): # Ensure that it is bytes blob = _to_bytes(blob, encoding='utf-8') return (self._private_key_id, - rsa.pkcs1.sign(blob, self._private_key, 'SHA-256')) + rsa.pkcs1.sign(blob, self._private_key, 'SHA-256')) @property def service_account_email(self): @@ -99,11 +101,11 @@ class _ServiceAccountCredentials(AssertionCredentials): @property def serialization_data(self): return { - 'type': 'service_account', - 'client_id': self._service_account_id, - 'client_email': self._service_account_email, - 'private_key_id': self._private_key_id, - 'private_key': self._private_key_pkcs8_text + 'type': 'service_account', + 'client_id': self._service_account_id, + 'client_email': self._service_account_email, + 'private_key_id': self._private_key_id, + 'private_key': self._private_key_pkcs8_text } def create_scoped_required(self): @@ -111,14 +113,14 @@ class _ServiceAccountCredentials(AssertionCredentials): def create_scoped(self, scopes): return _ServiceAccountCredentials(self._service_account_id, - self._service_account_email, - self._private_key_id, - self._private_key_pkcs8_text, - scopes, - user_agent=self._user_agent, - token_uri=self._token_uri, - revoke_uri=self._revoke_uri, - **self._kwargs) + self._service_account_email, + self._private_key_id, + self._private_key_pkcs8_text, + scopes, + user_agent=self._user_agent, + token_uri=self._token_uri, + revoke_uri=self._revoke_uri, + **self._kwargs) def _get_private_key(private_key_pkcs8_text): @@ -127,5 +129,5 @@ def _get_private_key(private_key_pkcs8_text): der = rsa.pem.load_pem(private_key_pkcs8_text, 'PRIVATE KEY') asn1_private_key, _ = decoder.decode(der, asn1Spec=PrivateKeyInfo()) return rsa.PrivateKey.load_pkcs1( - asn1_private_key.getComponentByName('privateKey').asOctets(), - format='DER') + asn1_private_key.getComponentByName('privateKey').asOctets(), + format='DER') diff --git a/oauth2client/tools.py b/oauth2client/tools.py index 45c27f5..f1977f6 100644 --- a/oauth2client/tools.py +++ b/oauth2client/tools.py @@ -55,14 +55,15 @@ def _CreateArgumentParser(): return None parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--auth_host_name', default='localhost', - help='Hostname when running a local web server.') + help='Hostname when running a local web server.') parser.add_argument('--noauth_local_webserver', action='store_true', - 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, - nargs='*', help='Port web server should listen on.') - parser.add_argument('--logging_level', default='ERROR', - choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], - help='Set the logging level of detail.') + nargs='*', help='Port web server should listen on.') + parser.add_argument( + '--logging_level', default='ERROR', + choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], + help='Set the logging level of detail.') return parser # argparser is an ArgumentParser that contains command-line options expected @@ -100,12 +101,14 @@ class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler): query = self.path.split('?', 1)[-1] query = dict(urllib.parse.parse_qsl(query)) self.server.query_params = query - self.wfile.write(b"Authentication Status") - self.wfile.write(b"

The authentication flow has completed.

") + self.wfile.write( + b"Authentication Status") + self.wfile.write( + b"

The authentication flow has completed.

") self.wfile.write(b"") 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) @@ -137,9 +140,9 @@ def run_flow(flow, storage, flags, http=None): Run a local web server to handle redirects during OAuth authorization. - The tools module defines an ``ArgumentParser`` the already contains the flag - definitions that ``run()`` requires. You can pass that ``ArgumentParser`` to - your ``ArgumentParser`` constructor:: + The tools module defines an ``ArgumentParser`` the already contains the + flag definitions that ``run()`` requires. You can pass that + ``ArgumentParser`` to your ``ArgumentParser`` constructor:: parser = argparse.ArgumentParser( description=__doc__, @@ -167,7 +170,7 @@ def run_flow(flow, storage, flags, http=None): port_number = port try: httpd = ClientRedirectServer((flags.auth_host_name, port), - ClientRedirectHandler) + ClientRedirectHandler) except socket.error: pass else: @@ -175,13 +178,14 @@ def run_flow(flow, storage, flags, http=None): break flags.noauth_local_webserver = not success if not success: - print('Failed to start a local webserver listening on either port 8080') - print('or port 9090. Please check your firewall settings and locally') - print('running programs that may be blocking or using those ports.') - print() - print('Falling back to --noauth_local_webserver and continuing with') - print('authorization.') - print() + print('Failed to start a local webserver listening ' + 'on either port 8080') + print('or port 9090. Please check your firewall settings and locally') + print('running programs that may be blocking or using those ports.') + print() + print('Falling back to --noauth_local_webserver and continuing with') + print('authorization.') + print() if not flags.noauth_local_webserver: oauth_callback = 'http://%s:%s/' % (flags.auth_host_name, port_number) @@ -197,7 +201,8 @@ def run_flow(flow, storage, flags, http=None): print() print(' ' + authorize_url) 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() print(' --noauth_local_webserver') @@ -216,7 +221,8 @@ def run_flow(flow, storage, flags, http=None): if 'code' in httpd.query_params: code = httpd.query_params['code'] 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.') else: code = input('Enter verification code: ').strip() @@ -235,15 +241,15 @@ def run_flow(flow, storage, flags, http=None): def message_if_missing(filename): """Helpful message to display if the CLIENT_SECRETS file is missing.""" - return _CLIENT_SECRETS_MESSAGE % filename + try: from oauth2client.old_run import run from oauth2client.old_run import FLAGS except ImportError: def run(*args, **kwargs): raise NotImplementedError( - 'The gflags library must be installed to use tools.run(). ' - 'Please install gflags or preferrably switch to using ' - 'tools.run_flow().') + 'The gflags library must be installed to use tools.run(). ' + 'Please install gflags or preferrably switch to using ' + 'tools.run_flow().') diff --git a/oauth2client/util.py b/oauth2client/util.py index f9a35f9..352afd8 100644 --- a/oauth2client/util.py +++ b/oauth2client/util.py @@ -129,8 +129,10 @@ def positional(max_positional_args): plural_s = '' if max_positional_args != 1: plural_s = 's' - message = '%s() takes at most %d positional argument%s (%d given)' % ( - wrapped.__name__, max_positional_args, plural_s, len(args)) + message = ('%s() takes at most %d positional ' + 'argument%s (%d given)' % ( + wrapped.__name__, max_positional_args, + plural_s, len(args))) if positional_parameters_enforcement == POSITIONAL_EXCEPTION: raise TypeError(message) elif positional_parameters_enforcement == POSITIONAL_WARNING: diff --git a/oauth2client/xsrfutil.py b/oauth2client/xsrfutil.py index e99876b..5c40832 100644 --- a/oauth2client/xsrfutil.py +++ b/oauth2client/xsrfutil.py @@ -104,7 +104,7 @@ def validate_token(key, token, user_id, action_id="", current_time=None): # The given token should match the generated one with the same time. expected_token = generate_token(key, user_id, action_id=action_id, - when=token_time) + when=token_time) if len(token) != len(expected_token): return False