Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/auth/_default.py: 18%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Copyright 2015 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15"""Application default credentials.
17Implements application default credentials and project ID detection.
18"""
19from __future__ import annotations
21import io
22import json
23import logging
24import os
25from typing import Optional, Sequence, TYPE_CHECKING
26import warnings
28from google.auth import environment_vars
29from google.auth import exceptions
31if TYPE_CHECKING: # pragma: NO COVER
32 import google.auth.credentials.Credentials # type: ignore
33 import google.auth.transport.Request # type: ignore
35_LOGGER = logging.getLogger(__name__)
37# Valid types accepted for file-based credentials.
38_AUTHORIZED_USER_TYPE = "authorized_user"
39_SERVICE_ACCOUNT_TYPE = "service_account"
40_EXTERNAL_ACCOUNT_TYPE = "external_account"
41_EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE = "external_account_authorized_user"
42_IMPERSONATED_SERVICE_ACCOUNT_TYPE = "impersonated_service_account"
43_GDCH_SERVICE_ACCOUNT_TYPE = "gdch_service_account"
44_VALID_TYPES = (
45 _AUTHORIZED_USER_TYPE,
46 _SERVICE_ACCOUNT_TYPE,
47 _EXTERNAL_ACCOUNT_TYPE,
48 _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE,
49 _IMPERSONATED_SERVICE_ACCOUNT_TYPE,
50 _GDCH_SERVICE_ACCOUNT_TYPE,
51)
53# Help message when no credentials can be found.
54_CLOUD_SDK_MISSING_CREDENTIALS = """\
55Your default credentials were not found. To set up Application Default Credentials, \
56see https://cloud.google.com/docs/authentication/external/set-up-adc for more information.\
57"""
59# Warning when using Cloud SDK user credentials
60_CLOUD_SDK_CREDENTIALS_WARNING = """\
61Your application has authenticated using end user credentials from Google \
62Cloud SDK without a quota project. You might receive a "quota exceeded" \
63or "API not enabled" error. See the following page for troubleshooting: \
64https://cloud.google.com/docs/authentication/adc-troubleshooting/user-creds. \
65"""
67_GENERIC_LOAD_METHOD_WARNING = """\
68The {} method is deprecated because of a potential security risk.
70This method does not validate the credential configuration. The security
71risk occurs when a credential configuration is accepted from a source that
72is not under your control and used without validation on your side.
74If you know that you will be loading credential configurations of a
75specific type, it is recommended to use a credential-type-specific
76load method.
77This will ensure that an unexpected credential type with potential for
78malicious intent is not loaded unintentionally. You might still have to do
79validation for certain credential types. Please follow the recommendations
80for that method. For example, if you want to load only service accounts,
81you can create the service account credentials explicitly:
83```
84from google.oauth2 import service_account
85creds = service_account.Credentials.from_service_account_file(filename)
86```
88If you are loading your credential configuration from an untrusted source and have
89not mitigated the risks (e.g. by validating the configuration yourself), make
90these changes as soon as possible to prevent security risks to your environment.
92Regardless of the method used, it is always your responsibility to validate
93configurations received from external sources.
95Refer to https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
96for more details.
97"""
99# The subject token type used for AWS external_account credentials.
100_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request"
103def _warn_about_problematic_credentials(credentials):
104 """Determines if the credentials are problematic.
106 Credentials from the Cloud SDK that are associated with Cloud SDK's project
107 are problematic because they may not have APIs enabled and have limited
108 quota. If this is the case, warn about it.
109 """
110 from google.auth import _cloud_sdk
112 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID:
113 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
116def _warn_about_generic_load_method(method_name): # pragma: NO COVER
117 """Warns that a generic load method is being used.
119 This is to discourage use of the generic load methods in favor of
120 more specific methods. The generic methods are more likely to lead to
121 security issues if the input is not validated.
123 Args:
124 method_name (str): The name of the method being used.
125 """
127 warnings.warn(_GENERIC_LOAD_METHOD_WARNING.format(method_name), DeprecationWarning)
130def load_credentials_from_file(
131 filename, scopes=None, default_scopes=None, quota_project_id=None, request=None
132):
133 """Loads Google credentials from a file.
135 The credentials file must be a service account key, stored authorized
136 user credentials, external account credentials, or impersonated service
137 account credentials.
139 .. warning::
140 Important: If you accept a credential configuration (credential JSON/File/Stream)
141 from an external source for authentication to Google Cloud Platform, you must
142 validate it before providing it to any Google API or client library. Providing an
143 unvalidated credential configuration to Google APIs or libraries can compromise
144 the security of your systems and data. For more information, refer to
145 `Validate credential configurations from external sources`_.
147 .. _Validate credential configurations from external sources:
148 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
150 Args:
151 filename (str): The full path to the credentials file.
152 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
153 specified, the credentials will automatically be scoped if
154 necessary
155 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
156 Google client library. Use 'scopes' for user-defined scopes.
157 quota_project_id (Optional[str]): The project ID used for
158 quota and billing.
159 request (Optional[google.auth.transport.Request]): An object used to make
160 HTTP requests. This is used to determine the associated project ID
161 for a workload identity pool resource (external account credentials).
162 If not specified, then it will use a
163 google.auth.transport.requests.Request client to make requests.
165 Returns:
166 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
167 credentials and the project ID. Authorized user credentials do not
168 have the project ID information. External account credentials project
169 IDs may not always be determined.
171 Raises:
172 google.auth.exceptions.DefaultCredentialsError: if the file is in the
173 wrong format or is missing.
174 """
175 _warn_about_generic_load_method("load_credentials_from_file")
177 if not os.path.exists(filename):
178 raise exceptions.DefaultCredentialsError(
179 "File {} was not found.".format(filename)
180 )
182 with io.open(filename, "r") as file_obj:
183 try:
184 info = json.load(file_obj)
185 except ValueError as caught_exc:
186 new_exc = exceptions.DefaultCredentialsError(
187 "File {} is not a valid json file.".format(filename), caught_exc
188 )
189 raise new_exc from caught_exc
190 return _load_credentials_from_info(
191 filename, info, scopes, default_scopes, quota_project_id, request
192 )
195def load_credentials_from_dict(
196 info, scopes=None, default_scopes=None, quota_project_id=None, request=None
197):
198 """Loads Google credentials from a dict.
200 The credentials file must be a service account key, stored authorized
201 user credentials, external account credentials, or impersonated service
202 account credentials.
204 .. warning::
205 Important: If you accept a credential configuration (credential JSON/File/Stream)
206 from an external source for authentication to Google Cloud Platform, you must
207 validate it before providing it to any Google API or client library. Providing an
208 unvalidated credential configuration to Google APIs or libraries can compromise
209 the security of your systems and data. For more information, refer to
210 `Validate credential configurations from external sources`_.
212 .. _Validate credential configurations from external sources:
213 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
215 Args:
216 info (Dict[str, Any]): A dict object containing the credentials
217 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
218 specified, the credentials will automatically be scoped if
219 necessary
220 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
221 Google client library. Use 'scopes' for user-defined scopes.
222 quota_project_id (Optional[str]): The project ID used for
223 quota and billing.
224 request (Optional[google.auth.transport.Request]): An object used to make
225 HTTP requests. This is used to determine the associated project ID
226 for a workload identity pool resource (external account credentials).
227 If not specified, then it will use a
228 google.auth.transport.requests.Request client to make requests.
230 Returns:
231 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
232 credentials and the project ID. Authorized user credentials do not
233 have the project ID information. External account credentials project
234 IDs may not always be determined.
236 Raises:
237 google.auth.exceptions.DefaultCredentialsError: if the file is in the
238 wrong format or is missing.
239 """
240 _warn_about_generic_load_method("load_credentials_from_dict")
241 if not isinstance(info, dict):
242 raise exceptions.DefaultCredentialsError(
243 "info object was of type {} but dict type was expected.".format(type(info))
244 )
246 return _load_credentials_from_info(
247 "dict object", info, scopes, default_scopes, quota_project_id, request
248 )
251def _load_credentials_from_info(
252 filename, info, scopes, default_scopes, quota_project_id, request
253):
254 from google.auth.credentials import CredentialsWithQuotaProject
256 credential_type = info.get("type")
258 if credential_type == _AUTHORIZED_USER_TYPE:
259 credentials, project_id = _get_authorized_user_credentials(
260 filename, info, scopes
261 )
263 elif credential_type == _SERVICE_ACCOUNT_TYPE:
264 credentials, project_id = _get_service_account_credentials(
265 filename, info, scopes, default_scopes
266 )
268 elif credential_type == _EXTERNAL_ACCOUNT_TYPE:
269 credentials, project_id = _get_external_account_credentials(
270 info,
271 filename,
272 scopes=scopes,
273 default_scopes=default_scopes,
274 request=request,
275 )
277 elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE:
278 credentials, project_id = _get_external_account_authorized_user_credentials(
279 filename, info, request
280 )
282 elif credential_type == _IMPERSONATED_SERVICE_ACCOUNT_TYPE:
283 credentials, project_id = _get_impersonated_service_account_credentials(
284 filename, info, scopes
285 )
286 elif credential_type == _GDCH_SERVICE_ACCOUNT_TYPE:
287 credentials, project_id = _get_gdch_service_account_credentials(filename, info)
288 else:
289 raise exceptions.DefaultCredentialsError(
290 "The file {file} does not have a valid type. "
291 "Type is {type}, expected one of {valid_types}.".format(
292 file=filename, type=credential_type, valid_types=_VALID_TYPES
293 )
294 )
295 if isinstance(credentials, CredentialsWithQuotaProject):
296 credentials = _apply_quota_project_id(credentials, quota_project_id)
297 return credentials, project_id
300def _get_gcloud_sdk_credentials(quota_project_id=None):
301 """Gets the credentials and project ID from the Cloud SDK."""
302 from google.auth import _cloud_sdk
304 _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...")
306 # Check if application default credentials exist.
307 credentials_filename = _cloud_sdk.get_application_default_credentials_path()
309 if not os.path.isfile(credentials_filename):
310 _LOGGER.debug("Cloud SDK credentials not found on disk; not using them")
311 return None, None
313 with warnings.catch_warnings():
314 warnings.simplefilter("ignore", DeprecationWarning)
315 credentials, project_id = load_credentials_from_file(
316 credentials_filename, quota_project_id=quota_project_id
317 )
318 credentials._cred_file_path = credentials_filename
320 if not project_id:
321 project_id = _cloud_sdk.get_project_id()
323 return credentials, project_id
326def _get_explicit_environ_credentials(quota_project_id=None):
327 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment
328 variable."""
329 from google.auth import _cloud_sdk
331 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path()
332 explicit_file = os.environ.get(environment_vars.CREDENTIALS, "")
334 _LOGGER.debug(
335 "Checking '%s' for explicit credentials as part of auth process...",
336 explicit_file,
337 )
339 if explicit_file != "" and explicit_file == cloud_sdk_adc_path:
340 # Cloud sdk flow calls gcloud to fetch project id, so if the explicit
341 # file path is cloud sdk credentials path, then we should fall back
342 # to cloud sdk flow, otherwise project id cannot be obtained.
343 _LOGGER.debug(
344 "Explicit credentials path '%s' is the same as Cloud SDK credentials path, fall back to Cloud SDK credentials flow...",
345 explicit_file,
346 )
347 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id)
349 if explicit_file != "":
350 with warnings.catch_warnings():
351 warnings.simplefilter("ignore", DeprecationWarning)
352 credentials, project_id = load_credentials_from_file(
353 os.environ[environment_vars.CREDENTIALS],
354 quota_project_id=quota_project_id,
355 )
356 credentials._cred_file_path = f"{explicit_file} file via the GOOGLE_APPLICATION_CREDENTIALS environment variable"
357 return credentials, project_id
359 else:
360 return None, None
363def _get_gae_credentials():
364 """Gets Google App Engine App Identity credentials and project ID."""
365 # If not GAE gen1, prefer the metadata service even if the GAE APIs are
366 # available as per https://google.aip.dev/auth/4115.
367 if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27":
368 return None, None
370 # While this library is normally bundled with app_engine, there are
371 # some cases where it's not available, so we tolerate ImportError.
372 try:
373 _LOGGER.debug("Checking for App Engine runtime as part of auth process...")
374 import google.auth.app_engine as app_engine
375 except ImportError:
376 _LOGGER.warning("Import of App Engine auth library failed.")
377 return None, None
379 try:
380 credentials = app_engine.Credentials()
381 project_id = app_engine.get_project_id()
382 return credentials, project_id
383 except EnvironmentError:
384 _LOGGER.debug(
385 "No App Engine library was found so cannot authentication via App Engine Identity Credentials."
386 )
387 return None, None
390def _get_gce_credentials(request=None, quota_project_id=None):
391 """Gets credentials and project ID from the GCE Metadata Service."""
392 # While this library is normally bundled with compute_engine, there are
393 # some cases where it's not available, so we tolerate ImportError.
394 # Compute Engine requires optional `requests` dependency.
395 try:
396 from google.auth import compute_engine
397 from google.auth.compute_engine import _metadata
398 import google.auth.transport.requests
399 except ImportError:
400 _LOGGER.warning("Import of Compute Engine auth library failed.")
401 return None, None
403 if request is None:
404 request = google.auth.transport.requests.Request()
406 if _metadata.is_on_gce(request=request):
407 # Get the project ID.
408 try:
409 project_id = _metadata.get_project_id(request=request)
410 except exceptions.TransportError:
411 project_id = None
413 cred = compute_engine.Credentials()
414 cred = _apply_quota_project_id(cred, quota_project_id)
416 return cred, project_id
417 else:
418 _LOGGER.warning(
419 "Authentication failed using Compute Engine authentication due to unavailable metadata server."
420 )
421 return None, None
424def _get_external_account_credentials(
425 info, filename, scopes=None, default_scopes=None, request=None
426):
427 """Loads external account Credentials from the parsed external account info.
429 The credentials information must correspond to a supported external account
430 credentials.
432 Args:
433 info (Mapping[str, str]): The external account info in Google format.
434 filename (str): The full path to the credentials file.
435 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
436 specified, the credentials will automatically be scoped if
437 necessary.
438 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
439 Google client library. Use 'scopes' for user-defined scopes.
440 request (Optional[google.auth.transport.Request]): An object used to make
441 HTTP requests. This is used to determine the associated project ID
442 for a workload identity pool resource (external account credentials).
443 If not specified, then it will use a
444 google.auth.transport.requests.Request client to make requests.
446 Returns:
447 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
448 credentials and the project ID. External account credentials project
449 IDs may not always be determined.
451 Raises:
452 google.auth.exceptions.DefaultCredentialsError: if the info dictionary
453 is in the wrong format or is missing required information.
454 """
455 # There are currently 3 types of external_account credentials.
456 if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE:
457 # Check if configuration corresponds to an AWS credentials.
458 from google.auth import aws
460 credentials = aws.Credentials.from_info(
461 info, scopes=scopes, default_scopes=default_scopes
462 )
463 elif (
464 info.get("credential_source") is not None
465 and info.get("credential_source").get("executable") is not None
466 ):
467 from google.auth import pluggable
469 credentials = pluggable.Credentials.from_info(
470 info, scopes=scopes, default_scopes=default_scopes
471 )
472 else:
473 try:
474 # Check if configuration corresponds to an Identity Pool credentials.
475 from google.auth import identity_pool
477 credentials = identity_pool.Credentials.from_info(
478 info, scopes=scopes, default_scopes=default_scopes
479 )
480 except ValueError:
481 # If the configuration is invalid or does not correspond to any
482 # supported external_account credentials, raise an error.
483 raise exceptions.DefaultCredentialsError(
484 "Failed to load external account credentials from {}".format(filename)
485 )
486 if request is None:
487 import google.auth.transport.requests
489 request = google.auth.transport.requests.Request()
491 return credentials, credentials.get_project_id(request=request)
494def _get_external_account_authorized_user_credentials(
495 filename, info, scopes=None, default_scopes=None, request=None
496):
497 try:
498 from google.auth import external_account_authorized_user
500 credentials = external_account_authorized_user.Credentials.from_info(info)
501 except ValueError:
502 raise exceptions.DefaultCredentialsError(
503 "Failed to load external account authorized user credentials from {}".format(
504 filename
505 )
506 )
508 return credentials, None
511def _get_authorized_user_credentials(filename, info, scopes=None):
512 from google.oauth2 import credentials
514 try:
515 credentials = credentials.Credentials.from_authorized_user_info(
516 info, scopes=scopes
517 )
518 except ValueError as caught_exc:
519 msg = "Failed to load authorized user credentials from {}".format(filename)
520 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
521 raise new_exc from caught_exc
522 return credentials, None
525def _get_service_account_credentials(filename, info, scopes=None, default_scopes=None):
526 from google.oauth2 import service_account
528 try:
529 credentials = service_account.Credentials.from_service_account_info(
530 info, scopes=scopes, default_scopes=default_scopes
531 )
532 except ValueError as caught_exc:
533 msg = "Failed to load service account credentials from {}".format(filename)
534 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
535 raise new_exc from caught_exc
536 return credentials, info.get("project_id")
539def _get_impersonated_service_account_credentials(filename, info, scopes):
540 from google.auth import impersonated_credentials
542 try:
543 credentials = (
544 impersonated_credentials.Credentials.from_impersonated_service_account_info(
545 info, scopes=scopes
546 )
547 )
548 except ValueError as caught_exc:
549 msg = "Failed to load impersonated service account credentials from {}".format(
550 filename
551 )
552 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
553 raise new_exc from caught_exc
554 return credentials, None
557def _get_gdch_service_account_credentials(filename, info):
558 from google.oauth2 import gdch_credentials
560 try:
561 credentials = (
562 gdch_credentials.ServiceAccountCredentials.from_service_account_info(info)
563 )
564 except ValueError as caught_exc:
565 msg = "Failed to load GDCH service account credentials from {}".format(filename)
566 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
567 raise new_exc from caught_exc
568 return credentials, info.get("project")
571def get_api_key_credentials(key):
572 """Return credentials with the given API key."""
573 from google.auth import api_key
575 return api_key.Credentials(key)
578def _apply_quota_project_id(credentials, quota_project_id):
579 if quota_project_id:
580 credentials = credentials.with_quota_project(quota_project_id)
581 else:
582 credentials = credentials.with_quota_project_from_environment()
584 from google.oauth2 import credentials as authorized_user_credentials
586 if isinstance(credentials, authorized_user_credentials.Credentials) and (
587 not credentials.quota_project_id
588 ):
589 _warn_about_problematic_credentials(credentials)
590 return credentials
593def default(
594 scopes: Optional[Sequence[str]] = None,
595 request: Optional["google.auth.transport.Request"] = None,
596 quota_project_id: Optional[str] = None,
597 default_scopes: Optional[Sequence[str]] = None,
598) -> tuple["google.auth.credentials.Credentials", Optional[str]]:
599 """Gets the default credentials for the current environment.
601 `Application Default Credentials`_ provides an easy way to obtain
602 credentials to call Google APIs for server-to-server or local applications.
603 This function acquires credentials from the environment in the following
604 order:
606 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
607 to the path of a valid service account JSON private key file, then it is
608 loaded and returned. The project ID returned is the project ID defined
609 in the service account file if available (some older files do not
610 contain project ID information).
612 If the environment variable is set to the path of a valid external
613 account JSON configuration file (workload identity federation), then the
614 configuration file is used to determine and retrieve the external
615 credentials from the current environment (AWS, Azure, etc).
616 These will then be exchanged for Google access tokens via the Google STS
617 endpoint.
618 The project ID returned in this case is the one corresponding to the
619 underlying workload identity pool resource if determinable.
621 If the environment variable is set to the path of a valid GDCH service
622 account JSON file (`Google Distributed Cloud Hosted`_), then a GDCH
623 credential will be returned. The project ID returned is the project
624 specified in the JSON file.
625 2. If the `Google Cloud SDK`_ is installed and has application default
626 credentials set they are loaded and returned.
628 To enable application default credentials with the Cloud SDK run::
630 gcloud auth application-default login
632 If the Cloud SDK has an active project, the project ID is returned. The
633 active project can be set using::
635 gcloud config set project
637 3. If the application is running in the `App Engine standard environment`_
638 (first generation) then the credentials and project ID from the
639 `App Identity Service`_ are used.
640 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
641 the `App Engine flexible environment`_ or the `App Engine standard
642 environment`_ (second generation) then the credentials and project ID
643 are obtained from the `Metadata Service`_.
644 5. If no credentials are found,
645 :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised.
647 .. _Application Default Credentials: https://developers.google.com\
648 /identity/protocols/application-default-credentials
649 .. _Google Cloud SDK: https://cloud.google.com/sdk
650 .. _App Engine standard environment: https://cloud.google.com/appengine
651 .. _App Identity Service: https://cloud.google.com/appengine/docs/python\
652 /appidentity/
653 .. _Compute Engine: https://cloud.google.com/compute
654 .. _App Engine flexible environment: https://cloud.google.com\
655 /appengine/flexible
656 .. _Metadata Service: https://cloud.google.com/compute/docs\
657 /storing-retrieving-metadata
658 .. _Cloud Run: https://cloud.google.com/run
659 .. _Google Distributed Cloud Hosted: https://cloud.google.com/blog/topics\
660 /hybrid-cloud/announcing-google-distributed-cloud-edge-and-hosted
662 Example::
664 import google.auth
666 credentials, project_id = google.auth.default()
668 Args:
669 scopes (Sequence[str]): The list of scopes for the credentials. If
670 specified, the credentials will automatically be scoped if
671 necessary.
672 request (Optional[google.auth.transport.Request]): An object used to make
673 HTTP requests. This is used to either detect whether the application
674 is running on Compute Engine or to determine the associated project
675 ID for a workload identity pool resource (external account
676 credentials). If not specified, then it will either use the standard
677 library http client to make requests for Compute Engine credentials
678 or a google.auth.transport.requests.Request client for external
679 account credentials.
680 quota_project_id (Optional[str]): The project ID used for
681 quota and billing.
682 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
683 Google client library. Use 'scopes' for user-defined scopes.
684 Returns:
685 Tuple[~google.auth.credentials.Credentials, Optional[str]]:
686 the current environment's credentials and project ID. Project ID
687 may be None, which indicates that the Project ID could not be
688 ascertained from the environment.
690 Raises:
691 ~google.auth.exceptions.DefaultCredentialsError:
692 If no credentials were found, or if the credentials found were
693 invalid.
694 """
695 from google.auth.credentials import with_scopes_if_required
696 from google.auth.credentials import CredentialsWithQuotaProject
698 explicit_project_id = os.environ.get(
699 environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
700 )
702 checkers = (
703 # Avoid passing scopes here to prevent passing scopes to user credentials.
704 # with_scopes_if_required() below will ensure scopes/default scopes are
705 # safely set on the returned credentials since requires_scopes will
706 # guard against setting scopes on user credentials.
707 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id),
708 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id),
709 _get_gae_credentials,
710 lambda: _get_gce_credentials(request, quota_project_id=quota_project_id),
711 )
713 for checker in checkers:
714 credentials, project_id = checker()
715 if credentials is not None:
716 credentials = with_scopes_if_required(
717 credentials, scopes, default_scopes=default_scopes
718 )
720 effective_project_id = explicit_project_id or project_id
722 # For external account credentials, scopes are required to determine
723 # the project ID. Try to get the project ID again if not yet
724 # determined.
725 if not effective_project_id and callable(
726 getattr(credentials, "get_project_id", None)
727 ):
728 if request is None:
729 import google.auth.transport.requests
731 request = google.auth.transport.requests.Request()
732 effective_project_id = credentials.get_project_id(request=request)
734 if quota_project_id and isinstance(
735 credentials, CredentialsWithQuotaProject
736 ):
737 credentials = credentials.with_quota_project(quota_project_id)
739 if not effective_project_id:
740 _LOGGER.warning(
741 "No project ID could be determined. Consider running "
742 "`gcloud config set project` or setting the %s "
743 "environment variable",
744 environment_vars.PROJECT,
745 )
746 return credentials, effective_project_id
748 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)