Making oauth2client/ files pass PEP8.
This commit is contained in:
		| @@ -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): | ||||
|   | ||||
| @@ -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()) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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.') | ||||
|   | ||||
| @@ -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) | ||||
|  | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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. | ||||
|         """ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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') | ||||
|   | ||||
| @@ -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"<html><head><title>Authentication Status</title></head>") | ||||
|         self.wfile.write(b"<body><p>The authentication flow has completed.</p>") | ||||
|         self.wfile.write( | ||||
|             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>") | ||||
|  | ||||
|     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().') | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Danny Hermes
					Danny Hermes