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

218 statements  

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. 

14 

15"""Application default credentials. 

16 

17Implements application default credentials and project ID detection. 

18""" 

19from __future__ import annotations 

20 

21import io 

22import json 

23import logging 

24import os 

25from typing import Optional, Sequence, TYPE_CHECKING 

26import warnings 

27 

28from google.auth import environment_vars 

29from google.auth import exceptions 

30import google.auth.transport._http_client 

31 

32if TYPE_CHECKING: # pragma: NO COVER 

33 from google.auth.credentials import Credentials # noqa: F401 

34 from google.auth.transport import Request # noqa: F401 

35 

36_LOGGER = logging.getLogger(__name__) 

37 

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) 

53 

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""" 

59 

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""" 

67 

68_GENERIC_LOAD_METHOD_WARNING = """\ 

69The {} method is deprecated because of a potential security risk. 

70 

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. 

74 

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: 

83 

84``` 

85from google.oauth2 import service_account 

86creds = service_account.Credentials.from_service_account_file(filename) 

87``` 

88 

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. 

92 

93Regardless of the method used, it is always your responsibility to validate 

94configurations received from external sources. 

95 

96Refer to https://cloud.google.com/docs/authentication/external/externally-sourced-credentials 

97for more details. 

98""" 

99 

100# The subject token type used for AWS external_account credentials. 

101_AWS_SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request" 

102 

103 

104def _warn_about_problematic_credentials(credentials): 

105 """Determines if the credentials are problematic. 

106 

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 

112 

113 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID: 

114 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING) 

115 

116 

117def _warn_about_generic_load_method(method_name): # pragma: NO COVER 

118 """Warns that a generic load method is being used. 

119 

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. 

123 

124 Args: 

125 method_name (str): The name of the method being used. 

126 """ 

127 

128 warnings.warn(_GENERIC_LOAD_METHOD_WARNING.format(method_name), DeprecationWarning) 

129 

130 

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. 

135 

136 The credentials file must be a service account key, stored authorized 

137 user credentials, external account credentials, or impersonated service 

138 account credentials. 

139 

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`_. 

147 

148 .. _Validate credential configurations from external sources: 

149 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials 

150 

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. 

165 

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. 

171 

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") 

177 

178 if not os.path.exists(filename): 

179 raise exceptions.DefaultCredentialsError( 

180 "File {} was not found.".format(filename) 

181 ) 

182 

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 ) 

194 

195 

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. 

200 

201 The credentials file must be a service account key, stored authorized 

202 user credentials, external account credentials, or impersonated service 

203 account credentials. 

204 

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`_. 

212 

213 .. _Validate credential configurations from external sources: 

214 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials 

215 

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. 

230 

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. 

236 

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 ) 

246 

247 return _load_credentials_from_info( 

248 "dict object", info, scopes, default_scopes, quota_project_id, request 

249 ) 

250 

251 

252def _load_credentials_from_info( 

253 filename, info, scopes, default_scopes, quota_project_id, request 

254): 

255 from google.auth.credentials import CredentialsWithQuotaProject 

256 

257 credential_type = info.get("type") 

258 

259 if credential_type == _AUTHORIZED_USER_TYPE: 

260 credentials, project_id = _get_authorized_user_credentials( 

261 filename, info, scopes 

262 ) 

263 

264 elif credential_type == _SERVICE_ACCOUNT_TYPE: 

265 credentials, project_id = _get_service_account_credentials( 

266 filename, info, scopes, default_scopes 

267 ) 

268 

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 ) 

277 

278 elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE: 

279 credentials, project_id = _get_external_account_authorized_user_credentials( 

280 filename, info, request 

281 ) 

282 

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 

299 

300 

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 

304 

305 _LOGGER.debug("Checking Cloud SDK credentials as part of auth process...") 

306 

307 # Check if application default credentials exist. 

308 credentials_filename = _cloud_sdk.get_application_default_credentials_path() 

309 

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 

313 

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 

320 

321 if not project_id: 

322 project_id = _cloud_sdk.get_project_id() 

323 

324 return credentials, project_id 

325 

326 

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 

331 

332 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() 

333 explicit_file = os.environ.get(environment_vars.CREDENTIALS, "") 

334 

335 _LOGGER.debug( 

336 "Checking '%s' for explicit credentials as part of auth process...", 

337 explicit_file, 

338 ) 

339 

340 if explicit_file != "" and explicit_file == cloud_sdk_adc_path: 

341 # Cloud sdk flow calls gcloud to fetch project id, so if the explicit 

342 # file path is cloud sdk credentials path, then we should fall back 

343 # to cloud sdk flow, otherwise project id cannot be obtained. 

344 _LOGGER.debug( 

345 "Explicit credentials path '%s' is the same as Cloud SDK credentials path, fall back to Cloud SDK credentials flow...", 

346 explicit_file, 

347 ) 

348 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id) 

349 

350 if explicit_file != "": 

351 with warnings.catch_warnings(): 

352 warnings.simplefilter("ignore", DeprecationWarning) 

353 credentials, project_id = load_credentials_from_file( 

354 os.environ[environment_vars.CREDENTIALS], 

355 quota_project_id=quota_project_id, 

356 ) 

357 credentials._cred_file_path = f"{explicit_file} file via the GOOGLE_APPLICATION_CREDENTIALS environment variable" 

358 return credentials, project_id 

359 

360 else: 

361 return None, None 

362 

363 

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 

370 

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 

379 

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 

389 

390 

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. 

397 

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 

406 

407 if request is None: 

408 request = google.auth.transport._http_client.Request() 

409 

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 

416 

417 cred = compute_engine.Credentials() 

418 cred = _apply_quota_project_id(cred, quota_project_id) 

419 

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 

426 

427 

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. 

432 

433 The credentials information must correspond to a supported external account 

434 credentials. 

435 

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. 

449 

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. 

454 

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 

463 

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 

472 

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 

480 

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 

492 

493 request = google.auth.transport.requests.Request() 

494 

495 return credentials, credentials.get_project_id(request=request) 

496 

497 

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 

503 

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 ) 

511 

512 return credentials, None 

513 

514 

515def _get_authorized_user_credentials(filename, info, scopes=None): 

516 from google.oauth2 import credentials 

517 

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 

527 

528 

529def _get_service_account_credentials(filename, info, scopes=None, default_scopes=None): 

530 from google.oauth2 import service_account 

531 

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") 

541 

542 

543def _get_impersonated_service_account_credentials(filename, info, scopes): 

544 from google.auth import impersonated_credentials 

545 

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 

559 

560 

561def _get_gdch_service_account_credentials(filename, info): 

562 from google.oauth2 import gdch_credentials 

563 

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") 

573 

574 

575def get_api_key_credentials(key): 

576 """Return credentials with the given API key.""" 

577 from google.auth import api_key 

578 

579 return api_key.Credentials(key) 

580 

581 

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() 

587 

588 from google.oauth2 import credentials as authorized_user_credentials 

589 

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 

595 

596 

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. 

604 

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: 

609 

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). 

615 

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. 

624 

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. 

631 

632 To enable application default credentials with the Cloud SDK run:: 

633 

634 gcloud auth application-default login 

635 

636 If the Cloud SDK has an active project, the project ID is returned. The 

637 active project can be set using:: 

638 

639 gcloud config set project 

640 

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. 

650 

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 

665 

666 Example:: 

667 

668 import google.auth 

669 

670 credentials, project_id = google.auth.default() 

671 

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. 

693 

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 

701 

702 explicit_project_id = os.environ.get( 

703 environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT) 

704 ) 

705 

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 ) 

716 

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 ) 

723 

724 effective_project_id = explicit_project_id or project_id 

725 

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 

734 

735 request = google.auth.transport.requests.Request() 

736 effective_project_id = credentials.get_project_id(request=request) 

737 

738 if quota_project_id and isinstance( 

739 credentials, CredentialsWithQuotaProject 

740 ): 

741 credentials = credentials.with_quota_project(quota_project_id) 

742 

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 

751 

752 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)