mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-04 11:43:45 +00:00
Upgrade to oauth2client 2.0.1. Remove support for seperate pem keys.
This commit is contained in:
@ -30,6 +30,7 @@ import tempfile
|
||||
import time
|
||||
import shutil
|
||||
import six
|
||||
from six.moves import http_client
|
||||
from six.moves import urllib
|
||||
|
||||
import httplib2
|
||||
@ -73,7 +74,7 @@ ID_TOKEN_VERIFICATON_CERTS = ID_TOKEN_VERIFICATION_CERTS
|
||||
OOB_CALLBACK_URN = 'urn:ietf:wg:oauth:2.0:oob'
|
||||
|
||||
# Google Data client libraries may need to set this to [401, 403].
|
||||
REFRESH_STATUS_CODES = [401]
|
||||
REFRESH_STATUS_CODES = (http_client.UNAUTHORIZED,)
|
||||
|
||||
# The value representing user credentials.
|
||||
AUTHORIZED_USER = 'authorized_user'
|
||||
@ -101,6 +102,8 @@ ADC_HELP_MSG = (
|
||||
'https://developers.google.com/accounts/docs/'
|
||||
'application-default-credentials for more information.')
|
||||
|
||||
_WELL_KNOWN_CREDENTIALS_FILE = 'application_default_credentials.json'
|
||||
|
||||
# The access token along with the seconds in which it expires.
|
||||
AccessTokenInfo = collections.namedtuple(
|
||||
'AccessTokenInfo', ['access_token', 'expires_in'])
|
||||
@ -115,6 +118,10 @@ _GCE_METADATA_HOST = '169.254.169.254'
|
||||
_METADATA_FLAVOR_HEADER = 'Metadata-Flavor'
|
||||
_DESIRED_METADATA_FLAVOR = 'Google'
|
||||
|
||||
# Expose utcnow() at module level to allow for
|
||||
# easier testing (by replacing with a stub).
|
||||
_UTCNOW = datetime.datetime.utcnow
|
||||
|
||||
|
||||
class SETTINGS(object):
|
||||
"""Settings namespace for globally defined values."""
|
||||
@ -133,6 +140,13 @@ class AccessTokenRefreshError(Error):
|
||||
"""Error trying to refresh an expired access token."""
|
||||
|
||||
|
||||
class HttpAccessTokenRefreshError(AccessTokenRefreshError):
|
||||
"""Error (with HTTP status) trying to refresh an expired access token."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HttpAccessTokenRefreshError, self).__init__(*args)
|
||||
self.status = kwargs.get('status')
|
||||
|
||||
|
||||
class TokenRevokeError(Error):
|
||||
"""Error trying to revoke a token."""
|
||||
|
||||
@ -185,6 +199,13 @@ class MemoryCache(object):
|
||||
self.cache.pop(key, None)
|
||||
|
||||
|
||||
def _parse_expiry(expiry):
|
||||
if expiry and isinstance(expiry, datetime.datetime):
|
||||
return expiry.strftime(EXPIRY_FORMAT)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class Credentials(object):
|
||||
"""Base class for all Credentials objects.
|
||||
|
||||
@ -195,7 +216,7 @@ class Credentials(object):
|
||||
JSON string as input and returns an instantiated Credentials object.
|
||||
"""
|
||||
|
||||
NON_SERIALIZED_MEMBERS = ['store']
|
||||
NON_SERIALIZED_MEMBERS = frozenset(['store'])
|
||||
|
||||
def authorize(self, http):
|
||||
"""Take an httplib2.Http instance (or equivalent) and authorizes it.
|
||||
@ -236,34 +257,37 @@ class Credentials(object):
|
||||
"""
|
||||
_abstract()
|
||||
|
||||
def _to_json(self, strip):
|
||||
def _to_json(self, strip, to_serialize=None):
|
||||
"""Utility function that creates JSON repr. of a Credentials object.
|
||||
|
||||
Args:
|
||||
strip: array, An array of names of members to not include in the
|
||||
strip: array, An array of names of members to exclude from the
|
||||
JSON.
|
||||
to_serialize: dict, (Optional) The properties for this object
|
||||
that will be serialized. This allows callers to modify
|
||||
before serializing.
|
||||
|
||||
Returns:
|
||||
string, a JSON representation of this instance, suitable to pass to
|
||||
from_json().
|
||||
"""
|
||||
t = type(self)
|
||||
d = copy.copy(self.__dict__)
|
||||
curr_type = self.__class__
|
||||
if to_serialize is None:
|
||||
to_serialize = copy.copy(self.__dict__)
|
||||
for member in strip:
|
||||
if member in d:
|
||||
del d[member]
|
||||
if (d.get('token_expiry') and
|
||||
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__
|
||||
d['_module'] = t.__module__
|
||||
for key, val in d.items():
|
||||
if member in to_serialize:
|
||||
del to_serialize[member]
|
||||
to_serialize['token_expiry'] = _parse_expiry(
|
||||
to_serialize.get('token_expiry'))
|
||||
# Add in information we will need later to reconstitute this instance.
|
||||
to_serialize['_class'] = curr_type.__name__
|
||||
to_serialize['_module'] = curr_type.__module__
|
||||
for key, val in to_serialize.items():
|
||||
if isinstance(val, bytes):
|
||||
d[key] = val.decode('utf-8')
|
||||
to_serialize[key] = val.decode('utf-8')
|
||||
if isinstance(val, set):
|
||||
d[key] = list(val)
|
||||
return json.dumps(d)
|
||||
to_serialize[key] = list(val)
|
||||
return json.dumps(to_serialize)
|
||||
|
||||
def to_json(self):
|
||||
"""Creating a JSON representation of an instance of Credentials.
|
||||
@ -272,23 +296,23 @@ class Credentials(object):
|
||||
string, a JSON representation of this instance, suitable to pass to
|
||||
from_json().
|
||||
"""
|
||||
return self._to_json(Credentials.NON_SERIALIZED_MEMBERS)
|
||||
return self._to_json(self.NON_SERIALIZED_MEMBERS)
|
||||
|
||||
@classmethod
|
||||
def new_from_json(cls, s):
|
||||
def new_from_json(cls, json_data):
|
||||
"""Utility class method to instantiate a Credentials subclass from JSON.
|
||||
|
||||
Expects the JSON string to have been produced by to_json().
|
||||
|
||||
Args:
|
||||
s: string or bytes, JSON from to_json().
|
||||
json_data: string or bytes, JSON from to_json().
|
||||
|
||||
Returns:
|
||||
An instance of the subclass of Credentials that was serialized with
|
||||
to_json().
|
||||
"""
|
||||
json_string_as_unicode = _from_bytes(s)
|
||||
data = json.loads(json_string_as_unicode)
|
||||
json_data_as_unicode = _from_bytes(json_data)
|
||||
data = json.loads(json_data_as_unicode)
|
||||
# Find and call the right classmethod from_json() to restore
|
||||
# the object.
|
||||
module_name = data['_module']
|
||||
@ -303,8 +327,7 @@ class Credentials(object):
|
||||
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)
|
||||
return kls.from_json(json_data_as_unicode)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, unused_data):
|
||||
@ -333,21 +356,31 @@ class Storage(object):
|
||||
such that multiple processes and threads can operate on a single
|
||||
store.
|
||||
"""
|
||||
def __init__(self, lock=None):
|
||||
"""Create a Storage instance.
|
||||
|
||||
Args:
|
||||
lock: An optional threading.Lock-like object. Must implement at
|
||||
least acquire() and release(). Does not need to be re-entrant.
|
||||
"""
|
||||
self._lock = lock
|
||||
|
||||
def acquire_lock(self):
|
||||
"""Acquires any lock necessary to access this Storage.
|
||||
|
||||
This lock is not reentrant.
|
||||
"""
|
||||
pass
|
||||
if self._lock is not None:
|
||||
self._lock.acquire()
|
||||
|
||||
def release_lock(self):
|
||||
"""Release the Storage lock.
|
||||
|
||||
Trying to release a lock that isn't held will result in a
|
||||
RuntimeError.
|
||||
RuntimeError in the case of a threading.Lock or multiprocessing.Lock.
|
||||
"""
|
||||
pass
|
||||
if self._lock is not None:
|
||||
self._lock.release()
|
||||
|
||||
def locked_get(self):
|
||||
"""Retrieve credential.
|
||||
@ -676,23 +709,19 @@ class OAuth2Credentials(Credentials):
|
||||
self._retrieve_scopes(http.request)
|
||||
return self.scopes
|
||||
|
||||
def to_json(self):
|
||||
return self._to_json(Credentials.NON_SERIALIZED_MEMBERS)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, s):
|
||||
def from_json(cls, json_data):
|
||||
"""Instantiate a Credentials object from a JSON description of it.
|
||||
|
||||
The JSON should have been produced by calling .to_json() on the object.
|
||||
|
||||
Args:
|
||||
data: dict, A deserialized JSON object.
|
||||
json_data: string or bytes, JSON to deserialize.
|
||||
|
||||
Returns:
|
||||
An instance of a Credentials subclass.
|
||||
"""
|
||||
s = _from_bytes(s)
|
||||
data = json.loads(s)
|
||||
data = json.loads(_from_bytes(json_data))
|
||||
if (data.get('token_expiry') and
|
||||
not isinstance(data['token_expiry'], datetime.datetime)):
|
||||
try:
|
||||
@ -728,7 +757,7 @@ class OAuth2Credentials(Credentials):
|
||||
if not self.token_expiry:
|
||||
return False
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
now = _UTCNOW()
|
||||
if now >= self.token_expiry:
|
||||
logger.info('access_token is expired. Now: %s, token_expiry: %s',
|
||||
now, self.token_expiry)
|
||||
@ -771,7 +800,7 @@ class OAuth2Credentials(Credentials):
|
||||
valid; we just don't know anything about it.
|
||||
"""
|
||||
if self.token_expiry:
|
||||
now = datetime.datetime.utcnow()
|
||||
now = _UTCNOW()
|
||||
if self.token_expiry > now:
|
||||
time_delta = self.token_expiry - now
|
||||
# TODO(orestica): return time_delta.total_seconds()
|
||||
@ -829,7 +858,7 @@ class OAuth2Credentials(Credentials):
|
||||
refresh request.
|
||||
|
||||
Raises:
|
||||
AccessTokenRefreshError: When the refresh fails.
|
||||
HttpAccessTokenRefreshError: When the refresh fails.
|
||||
"""
|
||||
if not self.store:
|
||||
self._do_refresh_request(http_request)
|
||||
@ -857,7 +886,7 @@ class OAuth2Credentials(Credentials):
|
||||
refresh request.
|
||||
|
||||
Raises:
|
||||
AccessTokenRefreshError: When the refresh fails.
|
||||
HttpAccessTokenRefreshError: When the refresh fails.
|
||||
"""
|
||||
body = self._generate_refresh_request_body()
|
||||
headers = self._generate_refresh_request_headers()
|
||||
@ -866,16 +895,20 @@ class OAuth2Credentials(Credentials):
|
||||
resp, content = http_request(
|
||||
self.token_uri, method='POST', body=body, headers=headers)
|
||||
content = _from_bytes(content)
|
||||
if resp.status == 200:
|
||||
if resp.status == http_client.OK:
|
||||
d = json.loads(content)
|
||||
self.token_response = d
|
||||
self.access_token = d['access_token']
|
||||
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()
|
||||
delta = datetime.timedelta(seconds=int(d['expires_in']))
|
||||
self.token_expiry = delta + _UTCNOW()
|
||||
else:
|
||||
self.token_expiry = None
|
||||
if 'id_token' in d:
|
||||
self.id_token = _extract_id_token(d['id_token'])
|
||||
else:
|
||||
self.id_token = None
|
||||
# On temporary refresh errors, the user does not actually have to
|
||||
# re-authorize, so we unflag here.
|
||||
self.invalid = False
|
||||
@ -897,7 +930,7 @@ class OAuth2Credentials(Credentials):
|
||||
self.store.locked_put(self)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
raise AccessTokenRefreshError(error_msg)
|
||||
raise HttpAccessTokenRefreshError(error_msg, status=resp.status)
|
||||
|
||||
def _revoke(self, http_request):
|
||||
"""Revokes this credential and deletes the stored copy (if it exists).
|
||||
@ -927,7 +960,7 @@ class OAuth2Credentials(Credentials):
|
||||
query_params = {'token': token}
|
||||
token_revoke_uri = _update_query_params(self.revoke_uri, query_params)
|
||||
resp, content = http_request(token_revoke_uri)
|
||||
if resp.status == 200:
|
||||
if resp.status == http_client.OK:
|
||||
self.invalid = True
|
||||
else:
|
||||
error_msg = 'Invalid response %s.' % resp.status
|
||||
@ -972,7 +1005,7 @@ class OAuth2Credentials(Credentials):
|
||||
query_params)
|
||||
resp, content = http_request(token_info_uri)
|
||||
content = _from_bytes(content)
|
||||
if resp.status == 200:
|
||||
if resp.status == http_client.OK:
|
||||
d = json.loads(content)
|
||||
self.scopes = set(util.string_to_scopes(d.get('scope', '')))
|
||||
else:
|
||||
@ -1036,8 +1069,8 @@ class AccessTokenCredentials(OAuth2Credentials):
|
||||
revoke_uri=revoke_uri)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, s):
|
||||
data = json.loads(_from_bytes(s))
|
||||
def from_json(cls, json_data):
|
||||
data = json.loads(_from_bytes(json_data))
|
||||
retval = AccessTokenCredentials(
|
||||
data['access_token'],
|
||||
data['user_agent'])
|
||||
@ -1078,7 +1111,7 @@ def _detect_gce_environment():
|
||||
headers = {_METADATA_FLAVOR_HEADER: _DESIRED_METADATA_FLAVOR}
|
||||
connection.request('GET', '/', headers=headers)
|
||||
response = connection.getresponse()
|
||||
if response.status == 200:
|
||||
if response.status == http_client.OK:
|
||||
return (response.getheader(_METADATA_FLAVOR_HEADER) ==
|
||||
_DESIRED_METADATA_FLAVOR)
|
||||
except socket.error: # socket.timeout or socket.error(64, 'Host is down')
|
||||
@ -1098,7 +1131,10 @@ def _in_gae_environment():
|
||||
return SETTINGS.env_name in ('GAE_PRODUCTION', 'GAE_LOCAL')
|
||||
|
||||
try:
|
||||
import google.appengine
|
||||
import google.appengine # noqa: unused import
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
server_software = os.environ.get(_SERVER_SOFTWARE, '')
|
||||
if server_software.startswith('Google App Engine/'):
|
||||
SETTINGS.env_name = 'GAE_PRODUCTION'
|
||||
@ -1106,8 +1142,6 @@ def _in_gae_environment():
|
||||
elif server_software.startswith('Development/'):
|
||||
SETTINGS.env_name = 'GAE_LOCAL'
|
||||
return True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
@ -1152,6 +1186,11 @@ class GoogleCredentials(OAuth2Credentials):
|
||||
print(response)
|
||||
"""
|
||||
|
||||
NON_SERIALIZED_MEMBERS = (
|
||||
frozenset(['_private_key']) |
|
||||
OAuth2Credentials.NON_SERIALIZED_MEMBERS)
|
||||
"""Members that aren't serialized when object is converted to JSON."""
|
||||
|
||||
def __init__(self, access_token, client_id, client_secret, refresh_token,
|
||||
token_expiry, token_uri, user_agent,
|
||||
revoke_uri=GOOGLE_REVOKE_URI):
|
||||
@ -1194,6 +1233,32 @@ class GoogleCredentials(OAuth2Credentials):
|
||||
"""
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_data):
|
||||
# TODO(issue 388): eliminate the circularity that is the reason for
|
||||
# this non-top-level import.
|
||||
from oauth2client.service_account import ServiceAccountCredentials
|
||||
data = json.loads(_from_bytes(json_data))
|
||||
|
||||
# We handle service_account.ServiceAccountCredentials since it is a
|
||||
# possible return type of GoogleCredentials.get_application_default()
|
||||
if (data['_module'] == 'oauth2client.service_account' and
|
||||
data['_class'] == 'ServiceAccountCredentials'):
|
||||
return ServiceAccountCredentials.from_json(data)
|
||||
|
||||
token_expiry = _parse_expiry(data.get('token_expiry'))
|
||||
google_credentials = cls(
|
||||
data['access_token'],
|
||||
data['client_id'],
|
||||
data['client_secret'],
|
||||
data['refresh_token'],
|
||||
token_expiry,
|
||||
data['token_uri'],
|
||||
data['user_agent'],
|
||||
revoke_uri=data.get('revoke_uri', None))
|
||||
google_credentials.invalid = data['invalid']
|
||||
return google_credentials
|
||||
|
||||
@property
|
||||
def serialization_data(self):
|
||||
"""Get the fields and values identifying the current credentials."""
|
||||
@ -1407,9 +1472,6 @@ def _get_well_known_file():
|
||||
"""Get the well known file produced by command 'gcloud auth login'."""
|
||||
# TODO(orestica): Revisit this method once gcloud provides a better way
|
||||
# of pinpointing the exact location of the file.
|
||||
|
||||
WELL_KNOWN_CREDENTIALS_FILE = 'application_default_credentials.json'
|
||||
|
||||
default_config_dir = os.getenv(_CLOUDSDK_CONFIG_ENV_VAR)
|
||||
if default_config_dir is None:
|
||||
if os.name == 'nt':
|
||||
@ -1427,14 +1489,11 @@ def _get_well_known_file():
|
||||
'.config',
|
||||
_CLOUDSDK_CONFIG_DIRECTORY)
|
||||
|
||||
return os.path.join(default_config_dir, WELL_KNOWN_CREDENTIALS_FILE)
|
||||
return os.path.join(default_config_dir, _WELL_KNOWN_CREDENTIALS_FILE)
|
||||
|
||||
|
||||
def _get_application_default_credential_from_file(filename):
|
||||
"""Build the Application Default Credentials from file."""
|
||||
|
||||
from oauth2client import service_account
|
||||
|
||||
# read the credentials from the file
|
||||
with open(filename) as file_obj:
|
||||
client_credentials = json.load(file_obj)
|
||||
@ -1465,12 +1524,9 @@ def _get_application_default_credential_from_file(filename):
|
||||
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=[])
|
||||
from oauth2client.service_account import ServiceAccountCredentials
|
||||
return ServiceAccountCredentials.from_json_keyfile_dict(
|
||||
client_credentials)
|
||||
|
||||
|
||||
def _raise_exception_for_missing_fields(missing_fields):
|
||||
@ -1487,15 +1543,15 @@ def _raise_exception_for_reading_json(credential_file,
|
||||
|
||||
|
||||
def _get_application_default_credential_GAE():
|
||||
from oauth2client.appengine import AppAssertionCredentials
|
||||
from oauth2client.contrib.appengine import AppAssertionCredentials
|
||||
|
||||
return AppAssertionCredentials([])
|
||||
|
||||
|
||||
def _get_application_default_credential_GCE():
|
||||
from oauth2client.gce import AppAssertionCredentials
|
||||
from oauth2client.contrib.gce import AppAssertionCredentials
|
||||
|
||||
return AppAssertionCredentials([])
|
||||
return AppAssertionCredentials()
|
||||
|
||||
|
||||
class AssertionCredentials(GoogleCredentials):
|
||||
@ -1561,6 +1617,18 @@ class AssertionCredentials(GoogleCredentials):
|
||||
"""
|
||||
self._do_revoke(http_request, self.access_token)
|
||||
|
||||
def sign_blob(self, blob):
|
||||
"""Cryptographically sign a blob (of bytes).
|
||||
|
||||
Args:
|
||||
blob: bytes, Message to be signed.
|
||||
|
||||
Returns:
|
||||
tuple, A pair of the private key ID used to sign the blob and
|
||||
the signed contents.
|
||||
"""
|
||||
raise NotImplementedError('This method is abstract.')
|
||||
|
||||
|
||||
def _RequireCryptoOrDie():
|
||||
"""Ensure we have a crypto library, or throw CryptoUnavailableError.
|
||||
@ -1573,102 +1641,6 @@ def _RequireCryptoOrDie():
|
||||
raise CryptoUnavailableError('No crypto library available')
|
||||
|
||||
|
||||
class SignedJwtAssertionCredentials(AssertionCredentials):
|
||||
"""Credentials object used for OAuth 2.0 Signed JWT assertion grants.
|
||||
|
||||
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.
|
||||
|
||||
SignedJwtAssertionCredentials requires either PyOpenSSL, or PyCrypto
|
||||
2.6 or later. For App Engine you may also consider using
|
||||
AppAssertionCredentials.
|
||||
"""
|
||||
|
||||
MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
|
||||
|
||||
@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):
|
||||
"""Constructor for SignedJwtAssertionCredentials.
|
||||
|
||||
Args:
|
||||
service_account_name: string, id for account, usually an email
|
||||
address.
|
||||
private_key: string, private key in PKCS12 or PEM format.
|
||||
scope: string or iterable of strings, scope(s) of the credentials
|
||||
being requested.
|
||||
private_key_password: string, password for private_key, unused if
|
||||
private_key is in PEM format.
|
||||
user_agent: string, HTTP User-Agent to provide for this
|
||||
application.
|
||||
token_uri: string, URI for token endpoint. For convenience defaults
|
||||
to Google's endpoints but any OAuth 2.0 provider can be
|
||||
used.
|
||||
revoke_uri: string, URI for revoke endpoint.
|
||||
kwargs: kwargs, Additional parameters to add to the JWT token, for
|
||||
example sub=joe@xample.org.
|
||||
|
||||
Raises:
|
||||
CryptoUnavailableError if no crypto library is available.
|
||||
"""
|
||||
_RequireCryptoOrDie()
|
||||
super(SignedJwtAssertionCredentials, self).__init__(
|
||||
None,
|
||||
user_agent=user_agent,
|
||||
token_uri=token_uri,
|
||||
revoke_uri=revoke_uri,
|
||||
)
|
||||
|
||||
self.scope = util.scopes_to_string(scope)
|
||||
|
||||
# Keep base64 encoded so it can be stored in JSON.
|
||||
self.private_key = base64.b64encode(private_key)
|
||||
self.private_key = _to_bytes(self.private_key, encoding='utf-8')
|
||||
self.private_key_password = private_key_password
|
||||
self.service_account_name = service_account_name
|
||||
self.kwargs = kwargs
|
||||
|
||||
@classmethod
|
||||
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']
|
||||
)
|
||||
retval.invalid = data['invalid']
|
||||
retval.access_token = data['access_token']
|
||||
return retval
|
||||
|
||||
def _generate_assertion(self):
|
||||
"""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
|
||||
}
|
||||
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)
|
||||
|
||||
# Only used in verify_id_token(), which is always calling to the same URI
|
||||
# for the certs.
|
||||
_cached_http = httplib2.Http(MemoryCache())
|
||||
@ -1702,7 +1674,7 @@ def verify_id_token(id_token, audience, http=None,
|
||||
http = _cached_http
|
||||
|
||||
resp, content = http.request(cert_uri)
|
||||
if resp.status == 200:
|
||||
if resp.status == http_client.OK:
|
||||
certs = json.loads(_from_bytes(content))
|
||||
return crypt.verify_signed_jwt_with_certs(id_token, certs, audience)
|
||||
else:
|
||||
@ -2047,7 +2019,7 @@ class OAuth2WebServerFlow(Flow):
|
||||
resp, content = http.request(self.device_uri, method='POST', body=body,
|
||||
headers=headers)
|
||||
content = _from_bytes(content)
|
||||
if resp.status == 200:
|
||||
if resp.status == http_client.OK:
|
||||
try:
|
||||
flow_info = json.loads(content)
|
||||
except ValueError as e:
|
||||
@ -2130,7 +2102,7 @@ class OAuth2WebServerFlow(Flow):
|
||||
resp, content = http.request(self.token_uri, method='POST', body=body,
|
||||
headers=headers)
|
||||
d = _parse_exchange_token_response(content)
|
||||
if resp.status == 200 and 'access_token' in d:
|
||||
if resp.status == http_client.OK and 'access_token' in d:
|
||||
access_token = d['access_token']
|
||||
refresh_token = d.get('refresh_token', None)
|
||||
if not refresh_token:
|
||||
@ -2139,9 +2111,8 @@ class OAuth2WebServerFlow(Flow):
|
||||
"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'])))
|
||||
delta = datetime.timedelta(seconds=int(d['expires_in']))
|
||||
token_expiry = delta + _UTCNOW()
|
||||
|
||||
extracted_id_token = None
|
||||
if 'id_token' in d:
|
||||
|
Reference in New Issue
Block a user