diff --git a/google/auth/_default.py b/google/auth/_default.py index 1f75be059..659350cc7 100644 --- a/google/auth/_default.py +++ b/google/auth/_default.py @@ -231,12 +231,13 @@ def default(scopes=None, request=None): gcloud config set project - 3. If the application is running in the `App Engine standard environment`_ - then the credentials and project ID from the `App Identity Service`_ - are used. - 4. If the application is running in `Compute Engine`_ or the - `App Engine flexible environment`_ then the credentials and project ID - are obtained from the `Metadata Service`_. + 3. If the application is running in the `App Engine standard first + generation environment`_ then the credentials and project ID from the + `App Identity Service`_ are used. + 4. If the application is running in `Compute Engine`_, the `App Engine + standard second generation environment`_, or the `App Engine flexible + environment`_ then the credentials and project ID are obtained from the + `Metadata Service`_. 5. If no credentials are found, :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised. diff --git a/google/auth/compute_engine/_metadata.py b/google/auth/compute_engine/_metadata.py index c47be3fae..de679e2a6 100644 --- a/google/auth/compute_engine/_metadata.py +++ b/google/auth/compute_engine/_metadata.py @@ -179,7 +179,8 @@ def get_service_account_info(request, service_account='default'): recursive=True) -def get_service_account_token(request, service_account='default'): +def get_service_account_token(request, service_account='default', + scopes=('https://www.googleapis.com/auth/cloud-platform')): """Get the OAuth 2.0 access token for a service account. Args: @@ -188,6 +189,8 @@ def get_service_account_token(request, service_account='default'): service_account (str): The string 'default' or a service account email address. The determines which service account for which to acquire an access token. + scopes (Sequence[str]): A list of OAuth scopes the token should contain. + Defaults to cloud-platform if not provided. Returns: Union[str, datetime]: The access token and its expiration. @@ -198,7 +201,7 @@ def get_service_account_token(request, service_account='default'): """ token_json = get( request, - 'instance/service-accounts/{0}/token'.format(service_account)) + 'instance/service-accounts/{0}/token?scopes={1}'.format(service_account, ",".join(scopes))) token_expiry = _helpers.utcnow() + datetime.timedelta( seconds=token_json['expires_in']) return token_json['access_token'], token_expiry diff --git a/google/auth/compute_engine/credentials.py b/google/auth/compute_engine/credentials.py index d9c6e26d6..916a2958d 100644 --- a/google/auth/compute_engine/credentials.py +++ b/google/auth/compute_engine/credentials.py @@ -32,7 +32,7 @@ from google.oauth2 import _client -class Credentials(credentials.ReadOnlyScoped, credentials.Credentials): +class Credentials(credentials.Scoped, credentials.Credentials): """Compute Engine Credentials. These credentials use the Google Compute Engine metadata server to obtain @@ -42,14 +42,6 @@ class Credentials(credentials.ReadOnlyScoped, credentials.Credentials): to configure scopes, see the `Compute Engine authentication documentation`_. - .. note:: Compute Engine instances can be created with scopes and therefore - these credentials are considered to be 'scoped'. However, you can - not use :meth:`~google.auth.credentials.ScopedCredentials.with_scopes` - because it is not possible to change the scopes that the instance - has. Also note that - :meth:`~google.auth.credentials.ScopedCredentials.has_scopes` will not - work until the credentials have been refreshed. - .. _Compute Engine authentication documentation: https://cloud.google.com/compute/docs/authentication#using """ @@ -96,7 +88,8 @@ def refresh(self, request): self._retrieve_info(request) self.token, self.expiry = _metadata.get_service_account_token( request, - service_account=self._service_account_email) + service_account=self._service_account_email, + scopes=self._scopes) except exceptions.TransportError as caught_exc: new_exc = exceptions.RefreshError(caught_exc) six.raise_from(new_exc, caught_exc) @@ -112,8 +105,18 @@ def service_account_email(self): @property def requires_scopes(self): - """False: Compute Engine credentials can not be scoped.""" - return False + """Compute Engine can be scoped by providing scopes to the metadata + service. + + Returns: + bool: True if there are no scopes set otherwise False. + """ + return not self._scopes + + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes): + return self.__class__( + scopes=scopes, service_account_id=self._service_account_id) _DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds