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"""
20import io
21import json
22import logging
23import os
24import warnings
26from google.auth import environment_vars
27from google.auth import exceptions
28import google.auth.transport._http_client
30_LOGGER = logging.getLogger(__name__)
32# Valid types accepted for file-based credentials.
33_AUTHORIZED_USER_TYPE = "authorized_user"
34_SERVICE_ACCOUNT_TYPE = "service_account"
35_EXTERNAL_ACCOUNT_TYPE = "external_account"
36_EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE = "external_account_authorized_user"
37_IMPERSONATED_SERVICE_ACCOUNT_TYPE = "impersonated_service_account"
38_GDCH_SERVICE_ACCOUNT_TYPE = "gdch_service_account"
39_VALID_TYPES = (
40 _AUTHORIZED_USER_TYPE,
41 _SERVICE_ACCOUNT_TYPE,
42 _EXTERNAL_ACCOUNT_TYPE,
43 _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE,
44 _IMPERSONATED_SERVICE_ACCOUNT_TYPE,
45 _GDCH_SERVICE_ACCOUNT_TYPE,
46)
48# Help message when no credentials can be found.
49_CLOUD_SDK_MISSING_CREDENTIALS = """\
50Your default credentials were not found. To set up Application Default Credentials, \
51see https://cloud.google.com/docs/authentication/external/set-up-adc for more information.\
52"""
54# Warning when using Cloud SDK user credentials
55_CLOUD_SDK_CREDENTIALS_WARNING = """\
56Your application has authenticated using end user credentials from Google \
57Cloud SDK without a quota project. You might receive a "quota exceeded" \
58or "API not enabled" error. See the following page for troubleshooting: \
59https://cloud.google.com/docs/authentication/adc-troubleshooting/user-creds. \
60"""
62_GENERIC_LOAD_METHOD_WARNING = """\
63The {} method is deprecated because of a potential security risk.
65This method does not validate the credential configuration. The security
66risk occurs when a credential configuration is accepted from a source that
67is not under your control and used without validation on your side.
69If you know that you will be loading credential configurations of a
70specific type, it is recommended to use a credential-type-specific
71load method.
72This will ensure that an unexpected credential type with potential for
73malicious intent is not loaded unintentionally. You might still have to do
74validation for certain credential types. Please follow the recommendations
75for that method. For example, if you want to load only service accounts,
76you can create the service account credentials explicitly:
78```
79from google.oauth2 import service_account
80creds = service_account.Credentials.from_service_account_file(filename)
81```
83If you are loading your credential configuration from an untrusted source and have
84not mitigated the risks (e.g. by validating the configuration yourself), make
85these changes as soon as possible to prevent security risks to your environment.
87Regardless of the method used, it is always your responsibility to validate
88configurations received from external sources.
90Refer to https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
91for more details.
92"""
94# The subject token type used for AWS external_account credentials.
95_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request"
98def _warn_about_problematic_credentials(credentials):
99 """Determines if the credentials are problematic.
101 Credentials from the Cloud SDK that are associated with Cloud SDK's project
102 are problematic because they may not have APIs enabled and have limited
103 quota. If this is the case, warn about it.
104 """
105 from google.auth import _cloud_sdk
107 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID:
108 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
111def _warn_about_generic_load_method(method_name): # pragma: NO COVER
112 """Warns that a generic load method is being used.
114 This is to discourage use of the generic load methods in favor of
115 more specific methods. The generic methods are more likely to lead to
116 security issues if the input is not validated.
118 Args:
119 method_name (str): The name of the method being used.
120 """
122 warnings.warn(_GENERIC_LOAD_METHOD_WARNING.format(method_name), DeprecationWarning)
125def load_credentials_from_file(
126 filename, scopes=None, default_scopes=None, quota_project_id=None, request=None
127):
128 """Loads Google credentials from a file.
130 The credentials file must be a service account key, stored authorized
131 user credentials, external account credentials, or impersonated service
132 account credentials.
134 .. warning::
135 Important: If you accept a credential configuration (credential JSON/File/Stream)
136 from an external source for authentication to Google Cloud Platform, you must
137 validate it before providing it to any Google API or client library. Providing an
138 unvalidated credential configuration to Google APIs or libraries can compromise
139 the security of your systems and data. For more information, refer to
140 `Validate credential configurations from external sources`_.
142 .. _Validate credential configurations from external sources:
143 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
145 Args:
146 filename (str): The full path to the credentials file.
147 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
148 specified, the credentials will automatically be scoped if
149 necessary
150 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
151 Google client library. Use 'scopes' for user-defined scopes.
152 quota_project_id (Optional[str]): The project ID used for
153 quota and billing.
154 request (Optional[google.auth.transport.Request]): An object used to make
155 HTTP requests. This is used to determine the associated project ID
156 for a workload identity pool resource (external account credentials).
157 If not specified, then it will use a
158 google.auth.transport.requests.Request client to make requests.
160 Returns:
161 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
162 credentials and the project ID. Authorized user credentials do not
163 have the project ID information. External account credentials project
164 IDs may not always be determined.
166 Raises:
167 google.auth.exceptions.DefaultCredentialsError: if the file is in the
168 wrong format or is missing.
169 """
170 _warn_about_generic_load_method("load_credentials_from_file")
172 if not os.path.exists(filename):
173 raise exceptions.DefaultCredentialsError(
174 "File {} was not found.".format(filename)
175 )
177 with io.open(filename, "r") as file_obj:
178 try:
179 info = json.load(file_obj)
180 except ValueError as caught_exc:
181 new_exc = exceptions.DefaultCredentialsError(
182 "File {} is not a valid json file.".format(filename), caught_exc
183 )
184 raise new_exc from caught_exc
185 return _load_credentials_from_info(
186 filename, info, scopes, default_scopes, quota_project_id, request
187 )
190def load_credentials_from_dict(
191 info, scopes=None, default_scopes=None, quota_project_id=None, request=None
192):
193 """Loads Google credentials from a dict.
195 The credentials file must be a service account key, stored authorized
196 user credentials, external account credentials, or impersonated service
197 account credentials.
199 .. warning::
200 Important: If you accept a credential configuration (credential JSON/File/Stream)
201 from an external source for authentication to Google Cloud Platform, you must
202 validate it before providing it to any Google API or client library. Providing an
203 unvalidated credential configuration to Google APIs or libraries can compromise
204 the security of your systems and data. For more information, refer to
205 `Validate credential configurations from external sources`_.
207 .. _Validate credential configurations from external sources:
208 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
210 Args:
211 info (Dict[str, Any]): A dict object containing the credentials
212 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
213 specified, the credentials will automatically be scoped if
214 necessary
215 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
216 Google client library. Use 'scopes' for user-defined scopes.
217 quota_project_id (Optional[str]): The project ID used for
218 quota and billing.
219 request (Optional[google.auth.transport.Request]): An object used to make
220 HTTP requests. This is used to determine the associated project ID
221 for a workload identity pool resource (external account credentials).
222 If not specified, then it will use a
223 google.auth.transport.requests.Request client to make requests.
225 Returns:
226 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
227 credentials and the project ID. Authorized user credentials do not
228 have the project ID information. External account credentials project
229 IDs may not always be determined.
231 Raises:
232 google.auth.exceptions.DefaultCredentialsError: if the file is in the
233 wrong format or is missing.
234 """
235 _warn_about_generic_load_method("load_credentials_from_dict")
236 if not isinstance(info, dict):
237 raise exceptions.DefaultCredentialsError(
238 "info object was of type {} but dict type was expected.".format(type(info))
239 )
241 return _load_credentials_from_info(
242 "dict object", info, scopes, default_scopes, quota_project_id, request
243 )
246def _load_credentials_from_info(
247 filename, info, scopes, default_scopes, quota_project_id, request
248):
249 from google.auth.credentials import CredentialsWithQuotaProject
251 credential_type = info.get("type")
253 if credential_type == _AUTHORIZED_USER_TYPE:
254 credentials, project_id = _get_authorized_user_credentials(
255 filename, info, scopes
256 )
258 elif credential_type == _SERVICE_ACCOUNT_TYPE:
259 credentials, project_id = _get_service_account_credentials(
260 filename, info, scopes, default_scopes
261 )
263 elif credential_type == _EXTERNAL_ACCOUNT_TYPE:
264 credentials, project_id = _get_external_account_credentials(
265 info,
266 filename,
267 scopes=scopes,
268 default_scopes=default_scopes,
269 request=request,
270 )
272 elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE:
273 credentials, project_id = _get_external_account_authorized_user_credentials(
274 filename, info, request
275 )
277 elif credential_type == _IMPERSONATED_SERVICE_ACCOUNT_TYPE:
278 credentials, project_id = _get_impersonated_service_account_credentials(
279 filename, info, scopes
280 )
281 elif credential_type == _GDCH_SERVICE_ACCOUNT_TYPE:
282 credentials, project_id = _get_gdch_service_account_credentials(filename, info)
283 else:
284 raise exceptions.DefaultCredentialsError(
285 "The file {file} does not have a valid type. "
286 "Type is {type}, expected one of {valid_types}.".format(
287 file=filename, type=credential_type, valid_types=_VALID_TYPES
288 )
289 )
290 if isinstance(credentials, CredentialsWithQuotaProject):
291 credentials = _apply_quota_project_id(credentials, quota_project_id)
292 return credentials, project_id
295def _get_gcloud_sdk_credentials(quota_project_id=None):
296 """Gets the credentials and project ID from the Cloud SDK."""
297 from google.auth import _cloud_sdk
299 _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...")
301 # Check if application default credentials exist.
302 credentials_filename = _cloud_sdk.get_application_default_credentials_path()
304 if not os.path.isfile(credentials_filename):
305 _LOGGER.debug("Cloud SDK credentials not found on disk; not using them")
306 return None, None
308 with warnings.catch_warnings():
309 warnings.simplefilter("ignore", DeprecationWarning)
310 credentials, project_id = load_credentials_from_file(
311 credentials_filename, quota_project_id=quota_project_id
312 )
313 credentials._cred_file_path = credentials_filename
315 if not project_id:
316 project_id = _cloud_sdk.get_project_id()
318 return credentials, project_id
321def _get_explicit_environ_credentials(quota_project_id=None):
322 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment
323 variable."""
324 from google.auth import _cloud_sdk
326 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path()
327 explicit_file = os.environ.get(environment_vars.CREDENTIALS)
329 _LOGGER.debug(
330 "Checking %s for explicit credentials as part of auth process...", explicit_file
331 )
333 if explicit_file is not None and explicit_file == cloud_sdk_adc_path:
334 # Cloud sdk flow calls gcloud to fetch project id, so if the explicit
335 # file path is cloud sdk credentials path, then we should fall back
336 # to cloud sdk flow, otherwise project id cannot be obtained.
337 _LOGGER.debug(
338 "Explicit credentials path %s is the same as Cloud SDK credentials path, fall back to Cloud SDK credentials flow...",
339 explicit_file,
340 )
341 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id)
343 if explicit_file is not None:
344 with warnings.catch_warnings():
345 warnings.simplefilter("ignore", DeprecationWarning)
346 credentials, project_id = load_credentials_from_file(
347 os.environ[environment_vars.CREDENTIALS],
348 quota_project_id=quota_project_id,
349 )
350 credentials._cred_file_path = f"{explicit_file} file via the GOOGLE_APPLICATION_CREDENTIALS environment variable"
352 return credentials, project_id
354 else:
355 return None, None
358def _get_gae_credentials():
359 """Gets Google App Engine App Identity credentials and project ID."""
360 # If not GAE gen1, prefer the metadata service even if the GAE APIs are
361 # available as per https://google.aip.dev/auth/4115.
362 if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27":
363 return None, None
365 # While this library is normally bundled with app_engine, there are
366 # some cases where it's not available, so we tolerate ImportError.
367 try:
368 _LOGGER.debug("Checking for App Engine runtime as part of auth process...")
369 import google.auth.app_engine as app_engine
370 except ImportError:
371 _LOGGER.warning("Import of App Engine auth library failed.")
372 return None, None
374 try:
375 credentials = app_engine.Credentials()
376 project_id = app_engine.get_project_id()
377 return credentials, project_id
378 except EnvironmentError:
379 _LOGGER.debug(
380 "No App Engine library was found so cannot authentication via App Engine Identity Credentials."
381 )
382 return None, None
385def _get_gce_credentials(request=None, quota_project_id=None):
386 """Gets credentials and project ID from the GCE Metadata Service."""
387 # Ping requires a transport, but we want application default credentials
388 # to require no arguments. So, we'll use the _http_client transport which
389 # uses http.client. This is only acceptable because the metadata server
390 # doesn't do SSL and never requires proxies.
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 try:
395 from google.auth import compute_engine
396 from google.auth.compute_engine import _metadata
397 except ImportError:
398 _LOGGER.warning("Import of Compute Engine auth library failed.")
399 return None, None
401 if request is None:
402 request = google.auth.transport._http_client.Request()
404 if _metadata.is_on_gce(request=request):
405 # Get the project ID.
406 try:
407 project_id = _metadata.get_project_id(request=request)
408 except exceptions.TransportError:
409 project_id = None
411 cred = compute_engine.Credentials()
412 cred = _apply_quota_project_id(cred, quota_project_id)
414 return cred, project_id
415 else:
416 _LOGGER.warning(
417 "Authentication failed using Compute Engine authentication due to unavailable metadata server."
418 )
419 return None, None
422def _get_external_account_credentials(
423 info, filename, scopes=None, default_scopes=None, request=None
424):
425 """Loads external account Credentials from the parsed external account info.
427 The credentials information must correspond to a supported external account
428 credentials.
430 Args:
431 info (Mapping[str, str]): The external account info in Google format.
432 filename (str): The full path to the credentials file.
433 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
434 specified, the credentials will automatically be scoped if
435 necessary.
436 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
437 Google client library. Use 'scopes' for user-defined scopes.
438 request (Optional[google.auth.transport.Request]): An object used to make
439 HTTP requests. This is used to determine the associated project ID
440 for a workload identity pool resource (external account credentials).
441 If not specified, then it will use a
442 google.auth.transport.requests.Request client to make requests.
444 Returns:
445 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
446 credentials and the project ID. External account credentials project
447 IDs may not always be determined.
449 Raises:
450 google.auth.exceptions.DefaultCredentialsError: if the info dictionary
451 is in the wrong format or is missing required information.
452 """
453 # There are currently 3 types of external_account credentials.
454 if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE:
455 # Check if configuration corresponds to an AWS credentials.
456 from google.auth import aws
458 credentials = aws.Credentials.from_info(
459 info, scopes=scopes, default_scopes=default_scopes
460 )
461 elif (
462 info.get("credential_source") is not None
463 and info.get("credential_source").get("executable") is not None
464 ):
465 from google.auth import pluggable
467 credentials = pluggable.Credentials.from_info(
468 info, scopes=scopes, default_scopes=default_scopes
469 )
470 else:
471 try:
472 # Check if configuration corresponds to an Identity Pool credentials.
473 from google.auth import identity_pool
475 credentials = identity_pool.Credentials.from_info(
476 info, scopes=scopes, default_scopes=default_scopes
477 )
478 except ValueError:
479 # If the configuration is invalid or does not correspond to any
480 # supported external_account credentials, raise an error.
481 raise exceptions.DefaultCredentialsError(
482 "Failed to load external account credentials from {}".format(filename)
483 )
484 if request is None:
485 import google.auth.transport.requests
487 request = google.auth.transport.requests.Request()
489 return credentials, credentials.get_project_id(request=request)
492def _get_external_account_authorized_user_credentials(
493 filename, info, scopes=None, default_scopes=None, request=None
494):
495 try:
496 from google.auth import external_account_authorized_user
498 credentials = external_account_authorized_user.Credentials.from_info(info)
499 except ValueError:
500 raise exceptions.DefaultCredentialsError(
501 "Failed to load external account authorized user credentials from {}".format(
502 filename
503 )
504 )
506 return credentials, None
509def _get_authorized_user_credentials(filename, info, scopes=None):
510 from google.oauth2 import credentials
512 try:
513 credentials = credentials.Credentials.from_authorized_user_info(
514 info, scopes=scopes
515 )
516 except ValueError as caught_exc:
517 msg = "Failed to load authorized user credentials from {}".format(filename)
518 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
519 raise new_exc from caught_exc
520 return credentials, None
523def _get_service_account_credentials(filename, info, scopes=None, default_scopes=None):
524 from google.oauth2 import service_account
526 try:
527 credentials = service_account.Credentials.from_service_account_info(
528 info, scopes=scopes, default_scopes=default_scopes
529 )
530 except ValueError as caught_exc:
531 msg = "Failed to load service account credentials from {}".format(filename)
532 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
533 raise new_exc from caught_exc
534 return credentials, info.get("project_id")
537def _get_impersonated_service_account_credentials(filename, info, scopes):
538 from google.auth import impersonated_credentials
540 try:
541 credentials = impersonated_credentials.Credentials.from_impersonated_service_account_info(
542 info, scopes=scopes
543 )
544 except ValueError as caught_exc:
545 msg = "Failed to load impersonated service account credentials from {}".format(
546 filename
547 )
548 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
549 raise new_exc from caught_exc
550 return credentials, None
553def _get_gdch_service_account_credentials(filename, info):
554 from google.oauth2 import gdch_credentials
556 try:
557 credentials = gdch_credentials.ServiceAccountCredentials.from_service_account_info(
558 info
559 )
560 except ValueError as caught_exc:
561 msg = "Failed to load GDCH service account credentials from {}".format(filename)
562 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
563 raise new_exc from caught_exc
564 return credentials, info.get("project")
567def get_api_key_credentials(key):
568 """Return credentials with the given API key."""
569 from google.auth import api_key
571 return api_key.Credentials(key)
574def _apply_quota_project_id(credentials, quota_project_id):
575 if quota_project_id:
576 credentials = credentials.with_quota_project(quota_project_id)
577 else:
578 credentials = credentials.with_quota_project_from_environment()
580 from google.oauth2 import credentials as authorized_user_credentials
582 if isinstance(credentials, authorized_user_credentials.Credentials) and (
583 not credentials.quota_project_id
584 ):
585 _warn_about_problematic_credentials(credentials)
586 return credentials
589def default(scopes=None, request=None, quota_project_id=None, default_scopes=None):
590 """Gets the default credentials for the current environment.
592 `Application Default Credentials`_ provides an easy way to obtain
593 credentials to call Google APIs for server-to-server or local applications.
594 This function acquires credentials from the environment in the following
595 order:
597 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set
598 to the path of a valid service account JSON private key file, then it is
599 loaded and returned. The project ID returned is the project ID defined
600 in the service account file if available (some older files do not
601 contain project ID information).
603 If the environment variable is set to the path of a valid external
604 account JSON configuration file (workload identity federation), then the
605 configuration file is used to determine and retrieve the external
606 credentials from the current environment (AWS, Azure, etc).
607 These will then be exchanged for Google access tokens via the Google STS
608 endpoint.
609 The project ID returned in this case is the one corresponding to the
610 underlying workload identity pool resource if determinable.
612 If the environment variable is set to the path of a valid GDCH service
613 account JSON file (`Google Distributed Cloud Hosted`_), then a GDCH
614 credential will be returned. The project ID returned is the project
615 specified in the JSON file.
616 2. If the `Google Cloud SDK`_ is installed and has application default
617 credentials set they are loaded and returned.
619 To enable application default credentials with the Cloud SDK run::
621 gcloud auth application-default login
623 If the Cloud SDK has an active project, the project ID is returned. The
624 active project can be set using::
626 gcloud config set project
628 3. If the application is running in the `App Engine standard environment`_
629 (first generation) then the credentials and project ID from the
630 `App Identity Service`_ are used.
631 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or
632 the `App Engine flexible environment`_ or the `App Engine standard
633 environment`_ (second generation) then the credentials and project ID
634 are obtained from the `Metadata Service`_.
635 5. If no credentials are found,
636 :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised.
638 .. _Application Default Credentials: https://developers.google.com\
639 /identity/protocols/application-default-credentials
640 .. _Google Cloud SDK: https://cloud.google.com/sdk
641 .. _App Engine standard environment: https://cloud.google.com/appengine
642 .. _App Identity Service: https://cloud.google.com/appengine/docs/python\
643 /appidentity/
644 .. _Compute Engine: https://cloud.google.com/compute
645 .. _App Engine flexible environment: https://cloud.google.com\
646 /appengine/flexible
647 .. _Metadata Service: https://cloud.google.com/compute/docs\
648 /storing-retrieving-metadata
649 .. _Cloud Run: https://cloud.google.com/run
650 .. _Google Distributed Cloud Hosted: https://cloud.google.com/blog/topics\
651 /hybrid-cloud/announcing-google-distributed-cloud-edge-and-hosted
653 Example::
655 import google.auth
657 credentials, project_id = google.auth.default()
659 Args:
660 scopes (Sequence[str]): The list of scopes for the credentials. If
661 specified, the credentials will automatically be scoped if
662 necessary.
663 request (Optional[google.auth.transport.Request]): An object used to make
664 HTTP requests. This is used to either detect whether the application
665 is running on Compute Engine or to determine the associated project
666 ID for a workload identity pool resource (external account
667 credentials). If not specified, then it will either use the standard
668 library http client to make requests for Compute Engine credentials
669 or a google.auth.transport.requests.Request client for external
670 account credentials.
671 quota_project_id (Optional[str]): The project ID used for
672 quota and billing.
673 default_scopes (Optional[Sequence[str]]): Default scopes passed by a
674 Google client library. Use 'scopes' for user-defined scopes.
675 Returns:
676 Tuple[~google.auth.credentials.Credentials, Optional[str]]:
677 the current environment's credentials and project ID. Project ID
678 may be None, which indicates that the Project ID could not be
679 ascertained from the environment.
681 Raises:
682 ~google.auth.exceptions.DefaultCredentialsError:
683 If no credentials were found, or if the credentials found were
684 invalid.
685 """
686 from google.auth.credentials import with_scopes_if_required
687 from google.auth.credentials import CredentialsWithQuotaProject
689 explicit_project_id = os.environ.get(
690 environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT)
691 )
693 checkers = (
694 # Avoid passing scopes here to prevent passing scopes to user credentials.
695 # with_scopes_if_required() below will ensure scopes/default scopes are
696 # safely set on the returned credentials since requires_scopes will
697 # guard against setting scopes on user credentials.
698 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id),
699 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id),
700 _get_gae_credentials,
701 lambda: _get_gce_credentials(request, quota_project_id=quota_project_id),
702 )
704 for checker in checkers:
705 credentials, project_id = checker()
706 if credentials is not None:
707 credentials = with_scopes_if_required(
708 credentials, scopes, default_scopes=default_scopes
709 )
711 effective_project_id = explicit_project_id or project_id
713 # For external account credentials, scopes are required to determine
714 # the project ID. Try to get the project ID again if not yet
715 # determined.
716 if not effective_project_id and callable(
717 getattr(credentials, "get_project_id", None)
718 ):
719 if request is None:
720 import google.auth.transport.requests
722 request = google.auth.transport.requests.Request()
723 effective_project_id = credentials.get_project_id(request=request)
725 if quota_project_id and isinstance(
726 credentials, CredentialsWithQuotaProject
727 ):
728 credentials = credentials.with_quota_project(quota_project_id)
730 if not effective_project_id:
731 _LOGGER.warning(
732 "No project ID could be determined. Consider running "
733 "`gcloud config set project` or setting the %s "
734 "environment variable",
735 environment_vars.PROJECT,
736 )
737 return credentials, effective_project_id
739 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)