Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Unified Diff: tools/telemetry/third_party/gsutil/third_party/apitools/apitools/base/py/credentials_lib.py

Issue 1260493004: Revert "Add gsutil 4.13 to telemetry/third_party" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/telemetry/third_party/gsutil/third_party/apitools/apitools/base/py/credentials_lib.py
diff --git a/tools/telemetry/third_party/gsutil/third_party/apitools/apitools/base/py/credentials_lib.py b/tools/telemetry/third_party/gsutil/third_party/apitools/apitools/base/py/credentials_lib.py
deleted file mode 100644
index 30789433e5fe86da0c13e91b40f1d2bbd1328ba0..0000000000000000000000000000000000000000
--- a/tools/telemetry/third_party/gsutil/third_party/apitools/apitools/base/py/credentials_lib.py
+++ /dev/null
@@ -1,489 +0,0 @@
-#!/usr/bin/env python
-"""Common credentials classes and constructors."""
-from __future__ import print_function
-
-import datetime
-import json
-import os
-
-import httplib2
-import oauth2client
-import oauth2client.client
-import oauth2client.gce
-import oauth2client.locked_file
-import oauth2client.multistore_file
-import oauth2client.service_account
-from oauth2client import tools # for gflags declarations
-from six.moves import http_client
-from six.moves import urllib
-
-from apitools.base.py import exceptions
-from apitools.base.py import util
-
-try:
- import gflags
- FLAGS = gflags.FLAGS
-except ImportError:
- FLAGS = None
-
-
-__all__ = [
- 'CredentialsFromFile',
- 'GaeAssertionCredentials',
- 'GceAssertionCredentials',
- 'GetCredentials',
- 'GetUserinfo',
- 'ServiceAccountCredentials',
- 'ServiceAccountCredentialsFromFile',
-]
-
-
-# TODO(craigcitro): Expose the extra args here somewhere higher up,
-# possibly as flags in the generated CLI.
-def GetCredentials(package_name, scopes, client_id, client_secret, user_agent,
- credentials_filename=None,
- service_account_name=None, service_account_keyfile=None,
- service_account_json_keyfile=None,
- api_key=None, # pylint: disable=unused-argument
- client=None): # pylint: disable=unused-argument
- """Attempt to get credentials, using an oauth dance as the last resort."""
- scopes = util.NormalizeScopes(scopes)
- if ((service_account_name and not service_account_keyfile) or
- (service_account_keyfile and not service_account_name)):
- raise exceptions.CredentialsError(
- 'Service account name or keyfile provided without the other')
- # TODO(craigcitro): Error checking.
- client_info = {
- 'client_id': client_id,
- 'client_secret': client_secret,
- 'scope': ' '.join(sorted(util.NormalizeScopes(scopes))),
- 'user_agent': user_agent or '%s-generated/0.1' % package_name,
- }
- service_account_kwargs = {
- 'user_agent': client_info['user_agent'],
- }
- if service_account_json_keyfile:
- with open(service_account_json_keyfile) as keyfile:
- service_account_info = json.load(keyfile)
- account_type = service_account_info.get('type')
- if account_type != oauth2client.client.SERVICE_ACCOUNT:
- raise exceptions.CredentialsError(
- 'Invalid service account credentials: %s' % (
- service_account_json_keyfile,))
- # pylint: disable=protected-access
- credentials = oauth2client.service_account._ServiceAccountCredentials(
- service_account_id=service_account_info['client_id'],
- service_account_email=service_account_info['client_email'],
- private_key_id=service_account_info['private_key_id'],
- private_key_pkcs8_text=service_account_info['private_key'],
- scopes=scopes,
- **service_account_kwargs)
- # pylint: enable=protected-access
- return credentials
- if service_account_name is not None:
- credentials = ServiceAccountCredentialsFromFile(
- service_account_name, service_account_keyfile, scopes,
- service_account_kwargs=service_account_kwargs)
- if credentials is not None:
- return credentials
- credentials = GaeAssertionCredentials.Get(scopes)
- if credentials is not None:
- return credentials
- credentials = GceAssertionCredentials.Get(scopes)
- if credentials is not None:
- return credentials
- credentials_filename = credentials_filename or os.path.expanduser(
- '~/.apitools.token')
- credentials = CredentialsFromFile(credentials_filename, client_info)
- if credentials is not None:
- return credentials
- raise exceptions.CredentialsError('Could not create valid credentials')
-
-
-def ServiceAccountCredentialsFromFile(
- service_account_name, private_key_filename, scopes,
- service_account_kwargs=None):
- with open(private_key_filename) as key_file:
- return ServiceAccountCredentials(
- service_account_name, key_file.read(), scopes,
- service_account_kwargs=service_account_kwargs)
-
-
-def ServiceAccountCredentials(service_account_name, private_key, scopes,
- service_account_kwargs=None):
- service_account_kwargs = service_account_kwargs or {}
- scopes = util.NormalizeScopes(scopes)
- return oauth2client.client.SignedJwtAssertionCredentials(
- service_account_name, private_key, scopes, **service_account_kwargs)
-
-
-def _EnsureFileExists(filename):
- """Touches a file; returns False on error, True on success."""
- if not os.path.exists(filename):
- old_umask = os.umask(0o177)
- try:
- open(filename, 'a+b').close()
- except OSError:
- return False
- finally:
- os.umask(old_umask)
- return True
-
-
-def _OpenNoProxy(request):
- """Wrapper around urllib2.open that ignores proxies."""
- opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
- return opener.open(request)
-
-
-# TODO(craigcitro): We override to add some utility code, and to
-# update the old refresh implementation. Push this code into
-# oauth2client.
-class GceAssertionCredentials(oauth2client.gce.AppAssertionCredentials):
-
- """Assertion credentials for GCE instances."""
-
- def __init__(self, scopes=None, service_account_name='default', **kwds):
- """Initializes the credentials instance.
-
- Args:
- scopes: The scopes to get. If None, whatever scopes that are
- available to the instance are used.
- service_account_name: The service account to retrieve the scopes
- from.
- **kwds: Additional keyword args.
-
- """
- # If there is a connectivity issue with the metadata server,
- # detection calls may fail even if we've already successfully
- # identified these scopes in the same execution. However, the
- # available scopes don't change once an instance is created,
- # so there is no reason to perform more than one query.
- #
- # TODO(craigcitro): Move this into oauth2client.
- self.__service_account_name = service_account_name
- cache_filename = None
- cached_scopes = None
- if 'cache_filename' in kwds:
- cache_filename = kwds['cache_filename']
- cached_scopes = self._CheckCacheFileForMatch(
- cache_filename, scopes)
-
- scopes = cached_scopes or self._ScopesFromMetadataServer(scopes)
-
- if cache_filename and not cached_scopes:
- self._WriteCacheFile(cache_filename, scopes)
-
- super(GceAssertionCredentials, self).__init__(scopes, **kwds)
-
- @classmethod
- def Get(cls, *args, **kwds):
- try:
- return cls(*args, **kwds)
- except exceptions.Error:
- return None
-
- def _CheckCacheFileForMatch(self, cache_filename, scopes):
- """Checks the cache file to see if it matches the given credentials.
-
- Args:
- cache_filename: Cache filename to check.
- scopes: Scopes for the desired credentials.
-
- Returns:
- List of scopes (if cache matches) or None.
- """
- creds = { # Credentials metadata dict.
- 'scopes': sorted(list(scopes)) if scopes else None,
- 'svc_acct_name': self.__service_account_name,
- }
- if _EnsureFileExists(cache_filename):
- locked_file = oauth2client.locked_file.LockedFile(
- cache_filename, 'r+b', 'rb')
- try:
- locked_file.open_and_lock()
- cached_creds_str = locked_file.file_handle().read()
- if cached_creds_str:
- # Cached credentials metadata dict.
- cached_creds = json.loads(cached_creds_str)
- if creds['svc_acct_name'] == cached_creds['svc_acct_name']:
- if creds['scopes'] in (None, cached_creds['scopes']):
- scopes = cached_creds['scopes']
- finally:
- locked_file.unlock_and_close()
- return scopes
-
- def _WriteCacheFile(self, cache_filename, scopes):
- """Writes the credential metadata to the cache file.
-
- This does not save the credentials themselves (CredentialStore class
- optionally handles that after this class is initialized).
-
- Args:
- cache_filename: Cache filename to check.
- scopes: Scopes for the desired credentials.
- """
- if _EnsureFileExists(cache_filename):
- locked_file = oauth2client.locked_file.LockedFile(
- cache_filename, 'r+b', 'rb')
- try:
- locked_file.open_and_lock()
- if locked_file.is_locked():
- creds = { # Credentials metadata dict.
- 'scopes': sorted(list(scopes)),
- 'svc_acct_name': self.__service_account_name}
- locked_file.file_handle().write(
- json.dumps(creds, encoding='ascii'))
- # If it's not locked, the locking process will
- # write the same data to the file, so just
- # continue.
- finally:
- locked_file.unlock_and_close()
-
- def _ScopesFromMetadataServer(self, scopes):
- if not util.DetectGce():
- raise exceptions.ResourceUnavailableError(
- 'GCE credentials requested outside a GCE instance')
- if not self.GetServiceAccount(self.__service_account_name):
- raise exceptions.ResourceUnavailableError(
- 'GCE credentials requested but service account '
- '%s does not exist.' % self.__service_account_name)
- if scopes:
- scope_ls = util.NormalizeScopes(scopes)
- instance_scopes = self.GetInstanceScopes()
- if scope_ls > instance_scopes:
- raise exceptions.CredentialsError(
- 'Instance did not have access to scopes %s' % (
- sorted(list(scope_ls - instance_scopes)),))
- else:
- scopes = self.GetInstanceScopes()
- return scopes
-
- def GetServiceAccount(self, account):
- account_uri = (
- 'http://metadata.google.internal/computeMetadata/'
- 'v1/instance/service-accounts')
- additional_headers = {'X-Google-Metadata-Request': 'True'}
- request = urllib.request.Request(
- account_uri, headers=additional_headers)
- try:
- response = _OpenNoProxy(request)
- except urllib.error.URLError as e:
- raise exceptions.CommunicationError(
- 'Could not reach metadata service: %s' % e.reason)
- response_lines = [line.rstrip('/\n\r')
- for line in response.readlines()]
- return account in response_lines
-
- def GetInstanceScopes(self):
- # Extra header requirement can be found here:
- # https://developers.google.com/compute/docs/metadata
- scopes_uri = (
- 'http://metadata.google.internal/computeMetadata/v1/instance/'
- 'service-accounts/%s/scopes') % self.__service_account_name
- additional_headers = {'X-Google-Metadata-Request': 'True'}
- request = urllib.request.Request(
- scopes_uri, headers=additional_headers)
- try:
- response = _OpenNoProxy(request)
- except urllib.error.URLError as e:
- raise exceptions.CommunicationError(
- 'Could not reach metadata service: %s' % e.reason)
- return util.NormalizeScopes(scope.strip()
- for scope in response.readlines())
-
- def _refresh(self, do_request):
- """Refresh self.access_token.
-
- This function replaces AppAssertionCredentials._refresh, which
- does not use the credential store and is therefore poorly
- suited for multi-threaded scenarios.
-
- Args:
- do_request: A function matching httplib2.Http.request's signature.
-
- """
- # pylint: disable=protected-access
- oauth2client.client.OAuth2Credentials._refresh(self, do_request)
- # pylint: enable=protected-access
-
- def _do_refresh_request(self, unused_http_request):
- """Refresh self.access_token by querying the metadata server.
-
- If self.store is initialized, store acquired credentials there.
- """
- token_uri = (
- 'http://metadata.google.internal/computeMetadata/v1/instance/'
- 'service-accounts/%s/token') % self.__service_account_name
- extra_headers = {'X-Google-Metadata-Request': 'True'}
- request = urllib.request.Request(token_uri, headers=extra_headers)
- try:
- content = _OpenNoProxy(request).read()
- except urllib.error.URLError as e:
- self.invalid = True
- if self.store:
- self.store.locked_put(self)
- raise exceptions.CommunicationError(
- 'Could not reach metadata service: %s' % e.reason)
- try:
- credential_info = json.loads(content)
- except ValueError:
- raise exceptions.CredentialsError(
- 'Invalid credentials response: uri %s' % token_uri)
-
- self.access_token = credential_info['access_token']
- if 'expires_in' in credential_info:
- expires_in = int(credential_info['expires_in'])
- self.token_expiry = (
- datetime.timedelta(seconds=expires_in) +
- datetime.datetime.utcnow())
- else:
- self.token_expiry = None
- self.invalid = False
- if self.store:
- self.store.locked_put(self)
-
- @classmethod
- def from_json(cls, json_data):
- data = json.loads(json_data)
- credentials = GceAssertionCredentials(scopes=[data['scope']])
- if 'access_token' in data:
- credentials.access_token = data['access_token']
- if 'token_expiry' in data:
- credentials.token_expiry = datetime.datetime.strptime(
- data['token_expiry'], oauth2client.client.EXPIRY_FORMAT)
- if 'invalid' in data:
- credentials.invalid = data['invalid']
- return credentials
-
- @property
- def serialization_data(self):
- raise NotImplementedError(
- 'Cannot serialize credentials for GCE service accounts.')
-
-
-# TODO(craigcitro): Currently, we can't even *load*
-# `oauth2client.appengine` without being on appengine, because of how
-# it handles imports. Fix that by splitting that module into
-# GAE-specific and GAE-independent bits, and guarding imports.
-class GaeAssertionCredentials(oauth2client.client.AssertionCredentials):
-
- """Assertion credentials for Google App Engine apps."""
-
- def __init__(self, scopes, **kwds):
- if not util.DetectGae():
- raise exceptions.ResourceUnavailableError(
- 'GCE credentials requested outside a GCE instance')
- self._scopes = list(util.NormalizeScopes(scopes))
- super(GaeAssertionCredentials, self).__init__(None, **kwds)
-
- @classmethod
- def Get(cls, *args, **kwds):
- try:
- return cls(*args, **kwds)
- except exceptions.Error:
- return None
-
- @classmethod
- def from_json(cls, json_data):
- data = json.loads(json_data)
- return GaeAssertionCredentials(data['_scopes'])
-
- def _refresh(self, _):
- """Refresh self.access_token.
-
- Args:
- _: (ignored) A function matching httplib2.Http.request's signature.
- """
- from google.appengine.api import app_identity
- try:
- token, _ = app_identity.get_access_token(self._scopes)
- except app_identity.Error as e:
- raise exceptions.CredentialsError(str(e))
- self.access_token = token
-
-
-def _GetRunFlowFlags(args=None):
- # There's one rare situation where gsutil will not have argparse
- # available, but doesn't need anything depending on argparse anyway,
- # since they're bringing their own credentials. So we just allow this
- # to fail with an ImportError in those cases.
- #
- # TODO(craigcitro): Move this import back to the top when we drop
- # python 2.6 support (eg when gsutil does).
- import argparse
-
- parser = argparse.ArgumentParser(parents=[tools.argparser])
- # Get command line argparse flags.
- flags = parser.parse_args(args=args)
-
- # Allow `gflags` and `argparse` to be used side-by-side.
- if hasattr(FLAGS, 'auth_host_name'):
- flags.auth_host_name = FLAGS.auth_host_name
- if hasattr(FLAGS, 'auth_host_port'):
- flags.auth_host_port = FLAGS.auth_host_port
- if hasattr(FLAGS, 'auth_local_webserver'):
- flags.noauth_local_webserver = (not FLAGS.auth_local_webserver)
- return flags
-
-
-# TODO(craigcitro): Switch this from taking a path to taking a stream.
-def CredentialsFromFile(path, client_info):
- """Read credentials from a file."""
- credential_store = oauth2client.multistore_file.get_credential_storage(
- path,
- client_info['client_id'],
- client_info['user_agent'],
- client_info['scope'])
- if hasattr(FLAGS, 'auth_local_webserver'):
- FLAGS.auth_local_webserver = False
- credentials = credential_store.get()
- if credentials is None or credentials.invalid:
- print('Generating new OAuth credentials ...')
- while True:
- # If authorization fails, we want to retry, rather than let this
- # cascade up and get caught elsewhere. If users want out of the
- # retry loop, they can ^C.
- try:
- flow = oauth2client.client.OAuth2WebServerFlow(**client_info)
- flags = _GetRunFlowFlags()
- credentials = tools.run_flow(flow, credential_store, flags)
- break
- except (oauth2client.client.FlowExchangeError, SystemExit) as e:
- # Here SystemExit is "no credential at all", and the
- # FlowExchangeError is "invalid" -- usually because you reused
- # a token.
- print('Invalid authorization: %s' % (e,))
- except httplib2.HttpLib2Error as e:
- print('Communication error: %s' % (e,))
- raise exceptions.CredentialsError(
- 'Communication error creating credentials: %s' % e)
- return credentials
-
-
-# TODO(craigcitro): Push this into oauth2client.
-def GetUserinfo(credentials, http=None): # pylint: disable=invalid-name
- """Get the userinfo associated with the given credentials.
-
- This is dependent on the token having either the userinfo.email or
- userinfo.profile scope for the given token.
-
- Args:
- credentials: (oauth2client.client.Credentials) incoming credentials
- http: (httplib2.Http, optional) http instance to use
-
- Returns:
- The email address for this token, or None if the required scopes
- aren't available.
- """
- http = http or httplib2.Http()
- url_root = 'https://www.googleapis.com/oauth2/v2/tokeninfo'
- query_args = {'access_token': credentials.access_token}
- url = '?'.join((url_root, urllib.parse.urlencode(query_args)))
- # We ignore communication woes here (i.e. SSL errors, socket
- # timeout), as handling these should be done in a common location.
- response, content = http.request(url)
- if response.status == http_client.BAD_REQUEST:
- credentials.refresh(http)
- response, content = http.request(url)
- return json.loads(content or '{}') # Save ourselves from an empty reply.

Powered by Google App Engine
This is Rietveld 408576698