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
30import google.auth.transport._http_client
32if TYPE_CHECKING: # pragma: NO COVER
33 from google.auth.credentials import Credentials # noqa: F401
34 from google.auth.transport import Request # noqa: F401
36_LOGGER = logging.getLogger(__name__)
38# Valid types accepted for file-based credentials.
39_AUTHORIZED_USER_TYPE = "authorized_user"
40_SERVICE_ACCOUNT_TYPE = "service_account"
41_EXTERNAL_ACCOUNT_TYPE = "external_account"
42_EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE = "external_account_authorized_user"
43_IMPERSONATED_SERVICE_ACCOUNT_TYPE = "impersonated_service_account"
44_GDCH_SERVICE_ACCOUNT_TYPE = "gdch_service_account"
45_VALID_TYPES = (
46 _AUTHORIZED_USER_TYPE,
47 _SERVICE_ACCOUNT_TYPE,
48 _EXTERNAL_ACCOUNT_TYPE,
49 _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE,
50 _IMPERSONATED_SERVICE_ACCOUNT_TYPE,
51 _GDCH_SERVICE_ACCOUNT_TYPE,
52)
54# Help message when no credentials can be found.
55_CLOUD_SDK_MISSING_CREDENTIALS = """\
56Your default credentials were not found. To set up Application Default Credentials, \
57see https://cloud.google.com/docs/authentication/external/set-up-adc for more information.\
58"""
60# Warning when using Cloud SDK user credentials
61_CLOUD_SDK_CREDENTIALS_WARNING = """\
62Your application has authenticated using end user credentials from Google \
63Cloud SDK without a quota project. You might receive a "quota exceeded" \
64or "API not enabled" error. See the following page for troubleshooting: \
65https://cloud.google.com/docs/authentication/adc-troubleshooting/user-creds. \
66"""
68_GENERIC_LOAD_METHOD_WARNING = """\
69The {} method is deprecated because of a potential security risk.
71This method does not validate the credential configuration. The security
72risk occurs when a credential configuration is accepted from a source that
73is not under your control and used without validation on your side.
75If you know that you will be loading credential configurations of a
76specific type, it is recommended to use a credential-type-specific
77load method.
78This will ensure that an unexpected credential type with potential for
79malicious intent is not loaded unintentionally. You might still have to do
80validation for certain credential types. Please follow the recommendations
81for that method. For example, if you want to load only service accounts,
82you can create the service account credentials explicitly:
84```
85from google.oauth2 import service_account
86creds = service_account.Credentials.from_service_account_file(filename)
87```
89If you are loading your credential configuration from an untrusted source and have
90not mitigated the risks (e.g. by validating the configuration yourself), make
91these changes as soon as possible to prevent security risks to your environment.
93Regardless of the method used, it is always your responsibility to validate
94configurations received from external sources.
96Refer to https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
97for more details.
98"""
100# The subject token type used for AWS external_account credentials.
101_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request"
104def _warn_about_problematic_credentials(credentials):
105 """Determines if the credentials are problematic.
107 Credentials from the Cloud SDK that are associated with Cloud SDK's project
108 are problematic because they may not have APIs enabled and have limited
109 quota. If this is the case, warn about it.
110 """
111 from google.auth import _cloud_sdk
113 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID:
114 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
117def _warn_about_generic_load_method(method_name): # pragma: NO COVER
118 """Warns that a generic load method is being used.
120 This is to discourage use of the generic load methods in favor of
121 more specific methods. The generic methods are more likely to lead to
122 security issues if the input is not validated.
124 Args:
125 method_name (str): The name of the method being used.
126 """
128 warnings.warn(_GENERIC_LOAD_METHOD_WARNING.format(method_name), DeprecationWarning)
131def load_credentials_from_file(
132 filename, scopes=None, default_scopes=None, quota_project_id=None, request=None
133):
134 """Loads Google credentials from a file.
136 The credentials file must be a service account key, stored authorized
137 user credentials, external account credentials, or impersonated service
138 account credentials.
140 .. warning::
141 Important: If you accept a credential configuration (credential JSON/File/Stream)
142 from an external source for authentication to Google Cloud Platform, you must
143 validate it before providing it to any Google API or client library. Providing an
144 unvalidated credential configuration to Google APIs or libraries can compromise
145 the security of your systems and data. For more information, refer to
146 `Validate credential configurations from external sources`_.
148 .. _Validate credential configurations from external sources:
149 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
151 Args:
152 filename (str): The full path to the credentials file.
153 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
154 specified, the credentials will automatically be scoped if
155 necessary
156 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
157 Google client library. Use 'scopes' for user-defined scopes.
158 quota_project_id (Optional[str]): The project ID used for
159 quota and billing.
160 request (Optional[google.auth.transport.Request]): An object used to make
161 HTTP requests. This is used to determine the associated project ID
162 for a workload identity pool resource (external account credentials).
163 If not specified, then it will use a
164 google.auth.transport.requests.Request client to make requests.
166 Returns:
167 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
168 credentials and the project ID. Authorized user credentials do not
169 have the project ID information. External account credentials project
170 IDs may not always be determined.
172 Raises:
173 google.auth.exceptions.DefaultCredentialsError: if the file is in the
174 wrong format or is missing.
175 """
176 _warn_about_generic_load_method("load_credentials_from_file")
178 if not os.path.exists(filename):
179 raise exceptions.DefaultCredentialsError(
180 "File {} was not found.".format(filename)
181 )
183 with io.open(filename, "r") as file_obj:
184 try:
185 info = json.load(file_obj)
186 except ValueError as caught_exc:
187 new_exc = exceptions.DefaultCredentialsError(
188 "File {} is not a valid json file.".format(filename), caught_exc
189 )
190 raise new_exc from caught_exc
191 return _load_credentials_from_info(
192 filename, info, scopes, default_scopes, quota_project_id, request
193 )
196def load_credentials_from_dict(
197 info, scopes=None, default_scopes=None, quota_project_id=None, request=None
198):
199 """Loads Google credentials from a dict.
201 The credentials file must be a service account key, stored authorized
202 user credentials, external account credentials, or impersonated service
203 account credentials.
205 .. warning::
206 Important: If you accept a credential configuration (credential JSON/File/Stream)
207 from an external source for authentication to Google Cloud Platform, you must
208 validate it before providing it to any Google API or client library. Providing an
209 unvalidated credential configuration to Google APIs or libraries can compromise
210 the security of your systems and data. For more information, refer to
211 `Validate credential configurations from external sources`_.
213 .. _Validate credential configurations from external sources:
214 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
216 Args:
217 info (Dict[str, Any]): A dict object containing the credentials
218 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
219 specified, the credentials will automatically be scoped if
220 necessary
221 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
222 Google client library. Use 'scopes' for user-defined scopes.
223 quota_project_id (Optional[str]): The project ID used for
224 quota and billing.
225 request (Optional[google.auth.transport.Request]): An object used to make
226 HTTP requests. This is used to determine the associated project ID
227 for a workload identity pool resource (external account credentials).
228 If not specified, then it will use a
229 google.auth.transport.requests.Request client to make requests.
231 Returns:
232 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
233 credentials and the project ID. Authorized user credentials do not
234 have the project ID information. External account credentials project
235 IDs may not always be determined.
237 Raises:
238 google.auth.exceptions.DefaultCredentialsError: if the file is in the
239 wrong format or is missing.
240 """
241 _warn_about_generic_load_method("load_credentials_from_dict")
242 if not isinstance(info, dict):
243 raise exceptions.DefaultCredentialsError(
244 "info object was of type {} but dict type was expected.".format(type(info))
245 )
247 return _load_credentials_from_info(
248 "dict object", info, scopes, default_scopes, quota_project_id, request
249 )
252def _load_credentials_from_info(
253 filename, info, scopes, default_scopes, quota_project_id, request
254):
255 from google.auth.credentials import CredentialsWithQuotaProject
257 credential_type = info.get("type")
259 if credential_type == _AUTHORIZED_USER_TYPE:
260 credentials, project_id = _get_authorized_user_credentials(
261 filename, info, scopes
262 )
264 elif credential_type == _SERVICE_ACCOUNT_TYPE:
265 credentials, project_id = _get_service_account_credentials(
266 filename, info, scopes, default_scopes
267 )
269 elif credential_type == _EXTERNAL_ACCOUNT_TYPE:
270 credentials, project_id = _get_external_account_credentials(
271 info,
272 filename,
273 scopes=scopes,
274 default_scopes=default_scopes,
275 request=request,
276 )
278 elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE:
279 credentials, project_id = _get_external_account_authorized_user_credentials(
280 filename, info, request
281 )
283 elif credential_type == _IMPERSONATED_SERVICE_ACCOUNT_TYPE:
284 credentials, project_id = _get_impersonated_service_account_credentials(
285 filename, info, scopes
286 )
287 elif credential_type == _GDCH_SERVICE_ACCOUNT_TYPE:
288 credentials, project_id = _get_gdch_service_account_credentials(filename, info)
289 else:
290 raise exceptions.DefaultCredentialsError(
291 "The file {file} does not have a valid type. "
292 "Type is {type}, expected one of {valid_types}.".format(
293 file=filename, type=credential_type, valid_types=_VALID_TYPES
294 )
295 )
296 if isinstance(credentials, CredentialsWithQuotaProject):
297 credentials = _apply_quota_project_id(credentials, quota_project_id)
298 return credentials, project_id
301def _get_gcloud_sdk_credentials(quota_project_id=None):
302 """Gets the credentials and project ID from the Cloud SDK."""
303 from google.auth import _cloud_sdk
305 _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...")
307 # Check if application default credentials exist.
308 credentials_filename = _cloud_sdk.get_application_default_credentials_path()
310 if not os.path.isfile(credentials_filename):
311 _LOGGER.debug("Cloud SDK credentials not found on disk; not using them")
312 return None, None
314 with warnings.catch_warnings():
315 warnings.simplefilter("ignore", DeprecationWarning)
316 credentials, project_id = load_credentials_from_file(
317 credentials_filename, quota_project_id=quota_project_id
318 )
319 credentials._cred_file_path = credentials_filename
321 if not project_id:
322 project_id = _cloud_sdk.get_project_id()
324 return credentials, project_id
327def _get_explicit_environ_credentials(quota_project_id=None):
328 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment
329 variable."""
330 from google.auth import _cloud_sdk
332 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path()
333 explicit_file = os.environ.get(environment_vars.CREDENTIALS)
335 _LOGGER.debug(
336 "Checking %s for explicit credentials as part of auth process...", explicit_file
337 )
339 if explicit_file is not None 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 is not None:
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"
358 return credentials, project_id
360 else:
361 return None, None
364def _get_gae_credentials():
365 """Gets Google App Engine App Identity credentials and project ID."""
366 # If not GAE gen1, prefer the metadata service even if the GAE APIs are
367 # available as per https://google.aip.dev/auth/4115.
368 if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27":
369 return None, None
371 # While this library is normally bundled with app_engine, there are
372 # some cases where it's not available, so we tolerate ImportError.
373 try:
374 _LOGGER.debug("Checking for App Engine runtime as part of auth process...")
375 import google.auth.app_engine as app_engine
376 except ImportError:
377 _LOGGER.warning("Import of App Engine auth library failed.")
378 return None, None
380 try:
381 credentials = app_engine.Credentials()
382 project_id = app_engine.get_project_id()
383 return credentials, project_id
384 except EnvironmentError:
385 _LOGGER.debug(
386 "No App Engine library was found so cannot authentication via App Engine Identity Credentials."
387 )
388 return None, None
391def _get_gce_credentials(request=None, quota_project_id=None):
392 """Gets credentials and project ID from the GCE Metadata Service."""
393 # Ping requires a transport, but we want application default credentials
394 # to require no arguments. So, we'll use the _http_client transport which
395 # uses http.client. This is only acceptable because the metadata server
396 # doesn't do SSL and never requires proxies.
398 # While this library is normally bundled with compute_engine, there are
399 # some cases where it's not available, so we tolerate ImportError.
400 try:
401 from google.auth import compute_engine
402 from google.auth.compute_engine import _metadata
403 except ImportError:
404 _LOGGER.warning("Import of Compute Engine auth library failed.")
405 return None, None
407 if request is None:
408 request = google.auth.transport._http_client.Request()
410 if _metadata.is_on_gce(request=request):
411 # Get the project ID.
412 try:
413 project_id = _metadata.get_project_id(request=request)
414 except exceptions.TransportError:
415 project_id = None
417 cred = compute_engine.Credentials()
418 cred = _apply_quota_project_id(cred, quota_project_id)
420 return cred, project_id
421 else:
422 _LOGGER.warning(
423 "Authentication failed using Compute Engine authentication due to unavailable metadata server."
424 )
425 return None, None
428def _get_external_account_credentials(
429 info, filename, scopes=None, default_scopes=None, request=None
430):
431 """Loads external account Credentials from the parsed external account info.
433 The credentials information must correspond to a supported external account
434 credentials.
436 Args:
437 info (Mapping[str, str]): The external account info in Google format.
438 filename (str): The full path to the credentials file.
439 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
440 specified, the credentials will automatically be scoped if
441 necessary.
442 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
443 Google client library. Use 'scopes' for user-defined scopes.
444 request (Optional[google.auth.transport.Request]): An object used to make
445 HTTP requests. This is used to determine the associated project ID
446 for a workload identity pool resource (external account credentials).
447 If not specified, then it will use a
448 google.auth.transport.requests.Request client to make requests.
450 Returns:
451 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
452 credentials and the project ID. External account credentials project
453 IDs may not always be determined.
455 Raises:
456 google.auth.exceptions.DefaultCredentialsError: if the info dictionary
457 is in the wrong format or is missing required information.
458 """
459 # There are currently 3 types of external_account credentials.
460 if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE:
461 # Check if configuration corresponds to an AWS credentials.
462 from google.auth import aws
464 credentials = aws.Credentials.from_info(
465 info, scopes=scopes, default_scopes=default_scopes
466 )
467 elif (
468 info.get("credential_source") is not None
469 and info.get("credential_source").get("executable") is not None
470 ):
471 from google.auth import pluggable
473 credentials = pluggable.Credentials.from_info(
474 info, scopes=scopes, default_scopes=default_scopes
475 )
476 else:
477 try:
478 # Check if configuration corresponds to an Identity Pool credentials.
479 from google.auth import identity_pool
481 credentials = identity_pool.Credentials.from_info(
482 info, scopes=scopes, default_scopes=default_scopes
483 )
484 except ValueError:
485 # If the configuration is invalid or does not correspond to any
486 # supported external_account credentials, raise an error.
487 raise exceptions.DefaultCredentialsError(
488 "Failed to load external account credentials from {}".format(filename)
489 )
490 if request is None:
491 import google.auth.transport.requests
493 request = google.auth.transport.requests.Request()
495 return credentials, credentials.get_project_id(request=request)
498def _get_external_account_authorized_user_credentials(
499 filename, info, scopes=None, default_scopes=None, request=None
500):
501 try:
502 from google.auth import external_account_authorized_user
504 credentials = external_account_authorized_user.Credentials.from_info(info)
505 except ValueError:
506 raise exceptions.DefaultCredentialsError(
507 "Failed to load external account authorized user credentials from {}".format(
508 filename
509 )
510 )
512 return credentials, None
515def _get_authorized_user_credentials(filename, info, scopes=None):
516 from google.oauth2 import credentials
518 try:
519 credentials = credentials.Credentials.from_authorized_user_info(
520 info, scopes=scopes
521 )
522 except ValueError as caught_exc:
523 msg = "Failed to load authorized user credentials from {}".format(filename)
524 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
525 raise new_exc from caught_exc
526 return credentials, None
529def _get_service_account_credentials(filename, info, scopes=None, default_scopes=None):
530 from google.oauth2 import service_account
532 try:
533 credentials = service_account.Credentials.from_service_account_info(
534 info, scopes=scopes, default_scopes=default_scopes
535 )
536 except ValueError as caught_exc:
537 msg = "Failed to load service account credentials from {}".format(filename)
538 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
539 raise new_exc from caught_exc
540 return credentials, info.get("project_id")
543def _get_impersonated_service_account_credentials(filename, info, scopes):
544 from google.auth import impersonated_credentials
546 try:
547 credentials = (
548 impersonated_credentials.Credentials.from_impersonated_service_account_info(
549 info, scopes=scopes
550 )
551 )
552 except ValueError as caught_exc:
553 msg = "Failed to load impersonated service account credentials from {}".format(
554 filename
555 )
556 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
557 raise new_exc from caught_exc
558 return credentials, None
561def _get_gdch_service_account_credentials(filename, info):
562 from google.oauth2 import gdch_credentials
564 try:
565 credentials = (
566 gdch_credentials.ServiceAccountCredentials.from_service_account_info(info)
567 )
568 except ValueError as caught_exc:
569 msg = "Failed to load GDCH service account credentials from {}".format(filename)
570 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
571 raise new_exc from caught_exc
572 return credentials, info.get("project")
575def get_api_key_credentials(key):
576 """Return credentials with the given API key."""
577 from google.auth import api_key
579 return api_key.Credentials(key)
582def _apply_quota_project_id(credentials, quota_project_id):
583 if quota_project_id:
584 credentials = credentials.with_quota_project(quota_project_id)
585 else:
586 credentials = credentials.with_quota_project_from_environment()
588 from google.oauth2 import credentials as authorized_user_credentials
590 if isinstance(credentials, authorized_user_credentials.Credentials) and (
591 not credentials.quota_project_id
592 ):
593 _warn_about_problematic_credentials(credentials)
594 return credentials
597def default(
598 scopes: Optional[Sequence[str]] = None,
599 request: Optional["google.auth.transport.Request"] = None,
600 quota_project_id: Optional[str] = None,
601 default_scopes: Optional[Sequence[str]] = None,
602) -> tuple["google.auth.credentials.Credentials", Optional[str]]:
603 """Gets the default credentials for the current environment.
605 `Application Default Credentials`_ provides an easy way to obtain
606 credentials to call Google APIs for server-to-server or local applications.
607 This function acquires credentials from the environment in the following
608 order:
610 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
611 to the path of a valid service account JSON private key file, then it is
612 loaded and returned. The project ID returned is the project ID defined
613 in the service account file if available (some older files do not
614 contain project ID information).
616 If the environment variable is set to the path of a valid external
617 account JSON configuration file (workload identity federation), then the
618 configuration file is used to determine and retrieve the external
619 credentials from the current environment (AWS, Azure, etc).
620 These will then be exchanged for Google access tokens via the Google STS
621 endpoint.
622 The project ID returned in this case is the one corresponding to the
623 underlying workload identity pool resource if determinable.
625 If the environment variable is set to the path of a valid GDCH service
626 account JSON file (`Google Distributed Cloud Hosted`_), then a GDCH
627 credential will be returned. The project ID returned is the project
628 specified in the JSON file.
629 2. If the `Google Cloud SDK`_ is installed and has application default
630 credentials set they are loaded and returned.
632 To enable application default credentials with the Cloud SDK run::
634 gcloud auth application-default login
636 If the Cloud SDK has an active project, the project ID is returned. The
637 active project can be set using::
639 gcloud config set project
641 3. If the application is running in the `App Engine standard environment`_
642 (first generation) then the credentials and project ID from the
643 `App Identity Service`_ are used.
644 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
645 the `App Engine flexible environment`_ or the `App Engine standard
646 environment`_ (second generation) then the credentials and project ID
647 are obtained from the `Metadata Service`_.
648 5. If no credentials are found,
649 :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised.
651 .. _Application Default Credentials: https://developers.google.com\
652 /identity/protocols/application-default-credentials
653 .. _Google Cloud SDK: https://cloud.google.com/sdk
654 .. _App Engine standard environment: https://cloud.google.com/appengine
655 .. _App Identity Service: https://cloud.google.com/appengine/docs/python\
656 /appidentity/
657 .. _Compute Engine: https://cloud.google.com/compute
658 .. _App Engine flexible environment: https://cloud.google.com\
659 /appengine/flexible
660 .. _Metadata Service: https://cloud.google.com/compute/docs\
661 /storing-retrieving-metadata
662 .. _Cloud Run: https://cloud.google.com/run
663 .. _Google Distributed Cloud Hosted: https://cloud.google.com/blog/topics\
664 /hybrid-cloud/announcing-google-distributed-cloud-edge-and-hosted
666 Example::
668 import google.auth
670 credentials, project_id = google.auth.default()
672 Args:
673 scopes (Sequence[str]): The list of scopes for the credentials. If
674 specified, the credentials will automatically be scoped if
675 necessary.
676 request (Optional[google.auth.transport.Request]): An object used to make
677 HTTP requests. This is used to either detect whether the application
678 is running on Compute Engine or to determine the associated project
679 ID for a workload identity pool resource (external account
680 credentials). If not specified, then it will either use the standard
681 library http client to make requests for Compute Engine credentials
682 or a google.auth.transport.requests.Request client for external
683 account credentials.
684 quota_project_id (Optional[str]): The project ID used for
685 quota and billing.
686 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
687 Google client library. Use 'scopes' for user-defined scopes.
688 Returns:
689 Tuple[~google.auth.credentials.Credentials, Optional[str]]:
690 the current environment's credentials and project ID. Project ID
691 may be None, which indicates that the Project ID could not be
692 ascertained from the environment.
694 Raises:
695 ~google.auth.exceptions.DefaultCredentialsError:
696 If no credentials were found, or if the credentials found were
697 invalid.
698 """
699 from google.auth.credentials import with_scopes_if_required
700 from google.auth.credentials import CredentialsWithQuotaProject
702 explicit_project_id = os.environ.get(
703 environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
704 )
706 checkers = (
707 # Avoid passing scopes here to prevent passing scopes to user credentials.
708 # with_scopes_if_required() below will ensure scopes/default scopes are
709 # safely set on the returned credentials since requires_scopes will
710 # guard against setting scopes on user credentials.
711 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id),
712 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id),
713 _get_gae_credentials,
714 lambda: _get_gce_credentials(request, quota_project_id=quota_project_id),
715 )
717 for checker in checkers:
718 credentials, project_id = checker()
719 if credentials is not None:
720 credentials = with_scopes_if_required(
721 credentials, scopes, default_scopes=default_scopes
722 )
724 effective_project_id = explicit_project_id or project_id
726 # For external account credentials, scopes are required to determine
727 # the project ID. Try to get the project ID again if not yet
728 # determined.
729 if not effective_project_id and callable(
730 getattr(credentials, "get_project_id", None)
731 ):
732 if request is None:
733 import google.auth.transport.requests
735 request = google.auth.transport.requests.Request()
736 effective_project_id = credentials.get_project_id(request=request)
738 if quota_project_id and isinstance(
739 credentials, CredentialsWithQuotaProject
740 ):
741 credentials = credentials.with_quota_project(quota_project_id)
743 if not effective_project_id:
744 _LOGGER.warning(
745 "No project ID could be determined. Consider running "
746 "`gcloud config set project` or setting the %s "
747 "environment variable",
748 environment_vars.PROJECT,
749 )
750 return credentials, effective_project_id
752 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)