Skip to content

Commit

Permalink
add support to async
Browse files Browse the repository at this point in the history
  • Loading branch information
arithmetic1728 committed Aug 6, 2021
1 parent ab03286 commit 385c113
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
10 changes: 7 additions & 3 deletions google/auth/_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@ def default(
order:
1. If `api_key` is provided or the environment variable ``GOOGLE_API_KEY`` is
set, an API key credentials will be returned. The provided `api_key` takes
precedence over the environment variable.
set, an `API Key`_ credentials will be returned. The provided `api_key`
takes precedence over the environment variable.
The project ID returned is the one defined by ``GOOGLE_CLOUD_PROJECT`` or
``GCLOUD_PROJECT`` environment variables.
2. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
Expand Down Expand Up @@ -420,6 +420,7 @@ def default(
.. _Metadata Service: https://cloud.google.com/compute/docs\
/storing-retrieving-metadata
.. _Cloud Run: https://cloud.google.com/run
.. _API Key: https://cloud.google.com/docs/authentication/api-keys
Example::
Expand Down Expand Up @@ -456,6 +457,7 @@ def default(
invalid.
"""
from google.auth.credentials import with_scopes_if_required
from google.auth.credentials import CredentialsWithQuotaProject

explicit_project_id = os.environ.get(
environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
Expand Down Expand Up @@ -490,7 +492,9 @@ def default(
request = google.auth.transport.requests.Request()
project_id = credentials.get_project_id(request=request)

if quota_project_id:
if quota_project_id and isinstance(
credentials, CredentialsWithQuotaProject
):
credentials = credentials.with_quota_project(quota_project_id)

effective_project_id = explicit_project_id or project_id
Expand Down
34 changes: 25 additions & 9 deletions google/auth/_default_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ def _get_gae_credentials():
return _default._get_gae_credentials()


def _get_api_key_credentials(api_key_string=None):
"""Gets API key credentials and project ID."""

return _default._get_api_key_credentials(api_key_string)


def _get_gce_credentials(request=None):
"""Gets credentials and project ID from the GCE Metadata Service."""
# Ping requires a transport, but we want application default credentials
Expand All @@ -168,20 +174,25 @@ def _get_gce_credentials(request=None):
return _default._get_gce_credentials(request)


def default_async(scopes=None, request=None, quota_project_id=None):
def default_async(scopes=None, request=None, quota_project_id=None, api_key=None):
"""Gets the default credentials for the current environment.
`Application Default Credentials`_ provides an easy way to obtain
credentials to call Google APIs for server-to-server or local applications.
This function acquires credentials from the environment in the following
order:
1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
1. If `api_key` is provided or the environment variable ``GOOGLE_API_KEY`` is
set, an `API Key`_ credentials will be returned. The provided `api_key`
takes precedence over the environment variable.
The project ID returned is the one defined by ``GOOGLE_CLOUD_PROJECT`` or
``GCLOUD_PROJECT`` environment variables.
2. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
to the path of a valid service account JSON private key file, then it is
loaded and returned. The project ID returned is the project ID defined
in the service account file if available (some older files do not
contain project ID information).
2. If the `Google Cloud SDK`_ is installed and has application default
3. If the `Google Cloud SDK`_ is installed and has application default
credentials set they are loaded and returned.
To enable application default credentials with the Cloud SDK run::
Expand All @@ -193,14 +204,14 @@ def default_async(scopes=None, request=None, quota_project_id=None):
gcloud config set project
3. If the application is running in the `App Engine standard environment`_
4. If the application is running in the `App Engine standard environment`_
(first generation) then the credentials and project ID from the
`App Identity Service`_ are used.
4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
5. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
the `App Engine flexible environment`_ or the `App Engine standard
environment`_ (second generation) then the credentials and project ID
are obtained from the `Metadata Service`_.
5. If no credentials are found,
6. If no credentials are found,
:class:`~google.auth.exceptions.DefaultCredentialsError` will be raised.
.. _Application Default Credentials: https://developers.google.com\
Expand All @@ -215,6 +226,7 @@ def default_async(scopes=None, request=None, quota_project_id=None):
.. _Metadata Service: https://cloud.google.com/compute/docs\
/storing-retrieving-metadata
.. _Cloud Run: https://cloud.google.com/run
.. _API Key: https://cloud.google.com/docs/authentication/api-keys
Example::
Expand Down Expand Up @@ -244,12 +256,14 @@ def default_async(scopes=None, request=None, quota_project_id=None):
invalid.
"""
from google.auth._credentials_async import with_scopes_if_required
from google.auth.credentials import CredentialsWithQuotaProject

explicit_project_id = os.environ.get(
environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
)

checkers = (
lambda: _get_api_key_credentials(api_key),
_get_explicit_environ_credentials,
_get_gcloud_sdk_credentials,
_get_gae_credentials,
Expand All @@ -259,9 +273,11 @@ def default_async(scopes=None, request=None, quota_project_id=None):
for checker in checkers:
credentials, project_id = checker()
if credentials is not None:
credentials = with_scopes_if_required(
credentials, scopes
).with_quota_project(quota_project_id)
credentials = with_scopes_if_required(credentials, scopes)
if quota_project_id and isinstance(
credentials, CredentialsWithQuotaProject
):
credentials = credentials.with_quota_project(quota_project_id)
effective_project_id = explicit_project_id or project_id
if not effective_project_id:
_default._LOGGER.warning(
Expand Down
2 changes: 1 addition & 1 deletion tests/test__default.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ def test_default_api_key(unused_get):
)
def test_default_api_key_from_env_var(unused_get):
with mock.patch.dict(os.environ, {environment_vars.API_KEY: "api-key"}):
cred, project_id = _default._get_api_key_credentials()
cred, project_id = _default.default()
assert isinstance(cred, api_key.Credentials)
assert cred.token == "api-key"
assert project_id is None
30 changes: 29 additions & 1 deletion tests_async/test__default_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from google.auth import _credentials_async as credentials
from google.auth import _default_async as _default
from google.auth import api_key
from google.auth import app_engine
from google.auth import compute_engine
from google.auth import environment_vars
Expand Down Expand Up @@ -509,7 +510,9 @@ def test_default_fail(unused_gce, unused_gae, unused_sdk, unused_explicit):
def test_default_scoped(with_scopes, unused_get):
scopes = ["one", "two"]

credentials, project_id = _default.default_async(scopes=scopes)
credentials, project_id = _default.default_async(
scopes=scopes, quota_project_id="project-foo"
)

assert credentials == with_scopes.return_value
assert project_id == mock.sentinel.project_id
Expand All @@ -533,3 +536,28 @@ def test_default_no_app_engine_compute_engine_module(unused_get):
sys.modules["google.auth.compute_engine"] = None
sys.modules["google.auth.app_engine"] = None
assert _default.default_async() == (MOCK_CREDENTIALS, mock.sentinel.project_id)


@mock.patch(
"google.auth._default_async._get_explicit_environ_credentials",
return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
autospec=True,
)
def test_default_api_key(unused_get):
cred, project_id = _default.default_async(api_key="api-key")
assert isinstance(cred, api_key.Credentials)
assert cred.token == "api-key"
assert project_id is None


@mock.patch(
"google.auth._default_async._get_explicit_environ_credentials",
return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
autospec=True,
)
def test_default_api_key_from_env_var(unused_get):
with mock.patch.dict(os.environ, {environment_vars.API_KEY: "api-key"}):
cred, project_id = _default.default_async()
assert isinstance(cred, api_key.Credentials)
assert cred.token == "api-key"
assert project_id is None

0 comments on commit 385c113

Please sign in to comment.