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

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

19 

20import io 

21import json 

22import logging 

23import os 

24import warnings 

25 

26from google.auth import environment_vars 

27from google.auth import exceptions 

28import google.auth.transport._http_client 

29 

30_LOGGER = logging.getLogger(__name__) 

31 

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) 

47 

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

53 

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

61 

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

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

64 

65 

66def _warn_about_problematic_credentials(credentials): 

67 """Determines if the credentials are problematic. 

68 

69 Credentials from the Cloud SDK that are associated with Cloud SDK's project 

70 are problematic because they may not have APIs enabled and have limited 

71 quota. If this is the case, warn about it. 

72 """ 

73 from google.auth import _cloud_sdk 

74 

75 if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID: 

76 warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING) 

77 

78 

79def load_credentials_from_file( 

80 filename, scopes=None, default_scopes=None, quota_project_id=None, request=None 

81): 

82 """Loads Google credentials from a file. 

83 

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

85 user credentials, external account credentials, or impersonated service 

86 account credentials. 

87 

88 .. warning:: 

89 Important: If you accept a credential configuration (credential JSON/File/Stream) 

90 from an external source for authentication to Google Cloud Platform, you must 

91 validate it before providing it to any Google API or client library. Providing an 

92 unvalidated credential configuration to Google APIs or libraries can compromise 

93 the security of your systems and data. For more information, refer to 

94 `Validate credential configurations from external sources`_. 

95 

96 .. _Validate credential configurations from external sources: 

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

98 

99 Args: 

100 filename (str): The full path to the credentials file. 

101 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If 

102 specified, the credentials will automatically be scoped if 

103 necessary 

104 default_scopes (Optional[Sequence[str]]): Default scopes passed by a 

105 Google client library. Use 'scopes' for user-defined scopes. 

106 quota_project_id (Optional[str]): The project ID used for 

107 quota and billing. 

108 request (Optional[google.auth.transport.Request]): An object used to make 

109 HTTP requests. This is used to determine the associated project ID 

110 for a workload identity pool resource (external account credentials). 

111 If not specified, then it will use a 

112 google.auth.transport.requests.Request client to make requests. 

113 

114 Returns: 

115 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded 

116 credentials and the project ID. Authorized user credentials do not 

117 have the project ID information. External account credentials project 

118 IDs may not always be determined. 

119 

120 Raises: 

121 google.auth.exceptions.DefaultCredentialsError: if the file is in the 

122 wrong format or is missing. 

123 """ 

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

125 raise exceptions.DefaultCredentialsError( 

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

127 ) 

128 

129 with io.open(filename, "r") as file_obj: 

130 try: 

131 info = json.load(file_obj) 

132 except ValueError as caught_exc: 

133 new_exc = exceptions.DefaultCredentialsError( 

134 "File {} is not a valid json file.".format(filename), caught_exc 

135 ) 

136 raise new_exc from caught_exc 

137 return _load_credentials_from_info( 

138 filename, info, scopes, default_scopes, quota_project_id, request 

139 ) 

140 

141 

142def load_credentials_from_dict( 

143 info, scopes=None, default_scopes=None, quota_project_id=None, request=None 

144): 

145 """Loads Google credentials from a dict. 

146 

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

148 user credentials, external account credentials, or impersonated service 

149 account credentials. 

150 

151 .. warning:: 

152 Important: If you accept a credential configuration (credential JSON/File/Stream) 

153 from an external source for authentication to Google Cloud Platform, you must 

154 validate it before providing it to any Google API or client library. Providing an 

155 unvalidated credential configuration to Google APIs or libraries can compromise 

156 the security of your systems and data. For more information, refer to 

157 `Validate credential configurations from external sources`_. 

158 

159 .. _Validate credential configurations from external sources: 

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

161 

162 Args: 

163 info (Dict[str, Any]): A dict object containing the credentials 

164 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If 

165 specified, the credentials will automatically be scoped if 

166 necessary 

167 default_scopes (Optional[Sequence[str]]): Default scopes passed by a 

168 Google client library. Use 'scopes' for user-defined scopes. 

169 quota_project_id (Optional[str]): The project ID used for 

170 quota and billing. 

171 request (Optional[google.auth.transport.Request]): An object used to make 

172 HTTP requests. This is used to determine the associated project ID 

173 for a workload identity pool resource (external account credentials). 

174 If not specified, then it will use a 

175 google.auth.transport.requests.Request client to make requests. 

176 

177 Returns: 

178 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded 

179 credentials and the project ID. Authorized user credentials do not 

180 have the project ID information. External account credentials project 

181 IDs may not always be determined. 

182 

183 Raises: 

184 google.auth.exceptions.DefaultCredentialsError: if the file is in the 

185 wrong format or is missing. 

186 """ 

187 if not isinstance(info, dict): 

188 raise exceptions.DefaultCredentialsError( 

189 "info object was of type {} but dict type was expected.".format(type(info)) 

190 ) 

191 

192 return _load_credentials_from_info( 

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

194 ) 

195 

196 

197def _load_credentials_from_info( 

198 filename, info, scopes, default_scopes, quota_project_id, request 

199): 

200 from google.auth.credentials import CredentialsWithQuotaProject 

201 

202 credential_type = info.get("type") 

203 

204 if credential_type == _AUTHORIZED_USER_TYPE: 

205 credentials, project_id = _get_authorized_user_credentials( 

206 filename, info, scopes 

207 ) 

208 

209 elif credential_type == _SERVICE_ACCOUNT_TYPE: 

210 credentials, project_id = _get_service_account_credentials( 

211 filename, info, scopes, default_scopes 

212 ) 

213 

214 elif credential_type == _EXTERNAL_ACCOUNT_TYPE: 

215 credentials, project_id = _get_external_account_credentials( 

216 info, 

217 filename, 

218 scopes=scopes, 

219 default_scopes=default_scopes, 

220 request=request, 

221 ) 

222 

223 elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE: 

224 credentials, project_id = _get_external_account_authorized_user_credentials( 

225 filename, info, request 

226 ) 

227 

228 elif credential_type == _IMPERSONATED_SERVICE_ACCOUNT_TYPE: 

229 credentials, project_id = _get_impersonated_service_account_credentials( 

230 filename, info, scopes 

231 ) 

232 elif credential_type == _GDCH_SERVICE_ACCOUNT_TYPE: 

233 credentials, project_id = _get_gdch_service_account_credentials(filename, info) 

234 else: 

235 raise exceptions.DefaultCredentialsError( 

236 "The file {file} does not have a valid type. " 

237 "Type is {type}, expected one of {valid_types}.".format( 

238 file=filename, type=credential_type, valid_types=_VALID_TYPES 

239 ) 

240 ) 

241 if isinstance(credentials, CredentialsWithQuotaProject): 

242 credentials = _apply_quota_project_id(credentials, quota_project_id) 

243 return credentials, project_id 

244 

245 

246def _get_gcloud_sdk_credentials(quota_project_id=None): 

247 """Gets the credentials and project ID from the Cloud SDK.""" 

248 from google.auth import _cloud_sdk 

249 

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

251 

252 # Check if application default credentials exist. 

253 credentials_filename = _cloud_sdk.get_application_default_credentials_path() 

254 

255 if not os.path.isfile(credentials_filename): 

256 _LOGGER.debug("Cloud SDK credentials not found on disk; not using them") 

257 return None, None 

258 

259 credentials, project_id = load_credentials_from_file( 

260 credentials_filename, quota_project_id=quota_project_id 

261 ) 

262 credentials._cred_file_path = credentials_filename 

263 

264 if not project_id: 

265 project_id = _cloud_sdk.get_project_id() 

266 

267 return credentials, project_id 

268 

269 

270def _get_explicit_environ_credentials(quota_project_id=None): 

271 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment 

272 variable.""" 

273 from google.auth import _cloud_sdk 

274 

275 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() 

276 explicit_file = os.environ.get(environment_vars.CREDENTIALS) 

277 

278 _LOGGER.debug( 

279 "Checking %s for explicit credentials as part of auth process...", explicit_file 

280 ) 

281 

282 if explicit_file is not None and explicit_file == cloud_sdk_adc_path: 

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

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

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

286 _LOGGER.debug( 

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

288 explicit_file, 

289 ) 

290 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id) 

291 

292 if explicit_file is not None: 

293 credentials, project_id = load_credentials_from_file( 

294 os.environ[environment_vars.CREDENTIALS], quota_project_id=quota_project_id 

295 ) 

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

297 

298 return credentials, project_id 

299 

300 else: 

301 return None, None 

302 

303 

304def _get_gae_credentials(): 

305 """Gets Google App Engine App Identity credentials and project ID.""" 

306 # If not GAE gen1, prefer the metadata service even if the GAE APIs are 

307 # available as per https://google.aip.dev/auth/4115. 

308 if os.environ.get(environment_vars.LEGACY_APPENGINE_RUNTIME) != "python27": 

309 return None, None 

310 

311 # While this library is normally bundled with app_engine, there are 

312 # some cases where it's not available, so we tolerate ImportError. 

313 try: 

314 _LOGGER.debug("Checking for App Engine runtime as part of auth process...") 

315 import google.auth.app_engine as app_engine 

316 except ImportError: 

317 _LOGGER.warning("Import of App Engine auth library failed.") 

318 return None, None 

319 

320 try: 

321 credentials = app_engine.Credentials() 

322 project_id = app_engine.get_project_id() 

323 return credentials, project_id 

324 except EnvironmentError: 

325 _LOGGER.debug( 

326 "No App Engine library was found so cannot authentication via App Engine Identity Credentials." 

327 ) 

328 return None, None 

329 

330 

331def _get_gce_credentials(request=None, quota_project_id=None): 

332 """Gets credentials and project ID from the GCE Metadata Service.""" 

333 # Ping requires a transport, but we want application default credentials 

334 # to require no arguments. So, we'll use the _http_client transport which 

335 # uses http.client. This is only acceptable because the metadata server 

336 # doesn't do SSL and never requires proxies. 

337 

338 # While this library is normally bundled with compute_engine, there are 

339 # some cases where it's not available, so we tolerate ImportError. 

340 try: 

341 from google.auth import compute_engine 

342 from google.auth.compute_engine import _metadata 

343 except ImportError: 

344 _LOGGER.warning("Import of Compute Engine auth library failed.") 

345 return None, None 

346 

347 if request is None: 

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

349 

350 if _metadata.is_on_gce(request=request): 

351 # Get the project ID. 

352 try: 

353 project_id = _metadata.get_project_id(request=request) 

354 except exceptions.TransportError: 

355 project_id = None 

356 

357 cred = compute_engine.Credentials() 

358 cred = _apply_quota_project_id(cred, quota_project_id) 

359 

360 return cred, project_id 

361 else: 

362 _LOGGER.warning( 

363 "Authentication failed using Compute Engine authentication due to unavailable metadata server." 

364 ) 

365 return None, None 

366 

367 

368def _get_external_account_credentials( 

369 info, filename, scopes=None, default_scopes=None, request=None 

370): 

371 """Loads external account Credentials from the parsed external account info. 

372 

373 The credentials information must correspond to a supported external account 

374 credentials. 

375 

376 Args: 

377 info (Mapping[str, str]): The external account info in Google format. 

378 filename (str): The full path to the credentials file. 

379 scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If 

380 specified, the credentials will automatically be scoped if 

381 necessary. 

382 default_scopes (Optional[Sequence[str]]): Default scopes passed by a 

383 Google client library. Use 'scopes' for user-defined scopes. 

384 request (Optional[google.auth.transport.Request]): An object used to make 

385 HTTP requests. This is used to determine the associated project ID 

386 for a workload identity pool resource (external account credentials). 

387 If not specified, then it will use a 

388 google.auth.transport.requests.Request client to make requests. 

389 

390 Returns: 

391 Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded 

392 credentials and the project ID. External account credentials project 

393 IDs may not always be determined. 

394 

395 Raises: 

396 google.auth.exceptions.DefaultCredentialsError: if the info dictionary 

397 is in the wrong format or is missing required information. 

398 """ 

399 # There are currently 3 types of external_account credentials. 

400 if info.get("subject_token_type") == _AWS_SUBJECT_TOKEN_TYPE: 

401 # Check if configuration corresponds to an AWS credentials. 

402 from google.auth import aws 

403 

404 credentials = aws.Credentials.from_info( 

405 info, scopes=scopes, default_scopes=default_scopes 

406 ) 

407 elif ( 

408 info.get("credential_source") is not None 

409 and info.get("credential_source").get("executable") is not None 

410 ): 

411 from google.auth import pluggable 

412 

413 credentials = pluggable.Credentials.from_info( 

414 info, scopes=scopes, default_scopes=default_scopes 

415 ) 

416 else: 

417 try: 

418 # Check if configuration corresponds to an Identity Pool credentials. 

419 from google.auth import identity_pool 

420 

421 credentials = identity_pool.Credentials.from_info( 

422 info, scopes=scopes, default_scopes=default_scopes 

423 ) 

424 except ValueError: 

425 # If the configuration is invalid or does not correspond to any 

426 # supported external_account credentials, raise an error. 

427 raise exceptions.DefaultCredentialsError( 

428 "Failed to load external account credentials from {}".format(filename) 

429 ) 

430 if request is None: 

431 import google.auth.transport.requests 

432 

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

434 

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

436 

437 

438def _get_external_account_authorized_user_credentials( 

439 filename, info, scopes=None, default_scopes=None, request=None 

440): 

441 try: 

442 from google.auth import external_account_authorized_user 

443 

444 credentials = external_account_authorized_user.Credentials.from_info(info) 

445 except ValueError: 

446 raise exceptions.DefaultCredentialsError( 

447 "Failed to load external account authorized user credentials from {}".format( 

448 filename 

449 ) 

450 ) 

451 

452 return credentials, None 

453 

454 

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

456 from google.oauth2 import credentials 

457 

458 try: 

459 credentials = credentials.Credentials.from_authorized_user_info( 

460 info, scopes=scopes 

461 ) 

462 except ValueError as caught_exc: 

463 msg = "Failed to load authorized user credentials from {}".format(filename) 

464 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

465 raise new_exc from caught_exc 

466 return credentials, None 

467 

468 

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

470 from google.oauth2 import service_account 

471 

472 try: 

473 credentials = service_account.Credentials.from_service_account_info( 

474 info, scopes=scopes, default_scopes=default_scopes 

475 ) 

476 except ValueError as caught_exc: 

477 msg = "Failed to load service account credentials from {}".format(filename) 

478 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

479 raise new_exc from caught_exc 

480 return credentials, info.get("project_id") 

481 

482 

483def _get_impersonated_service_account_credentials(filename, info, scopes): 

484 from google.auth import impersonated_credentials 

485 

486 try: 

487 credentials = impersonated_credentials.Credentials.from_impersonated_service_account_info( 

488 info, scopes=scopes 

489 ) 

490 except ValueError as caught_exc: 

491 msg = "Failed to load impersonated service account credentials from {}".format( 

492 filename 

493 ) 

494 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

495 raise new_exc from caught_exc 

496 return credentials, None 

497 

498 

499def _get_gdch_service_account_credentials(filename, info): 

500 from google.oauth2 import gdch_credentials 

501 

502 try: 

503 credentials = gdch_credentials.ServiceAccountCredentials.from_service_account_info( 

504 info 

505 ) 

506 except ValueError as caught_exc: 

507 msg = "Failed to load GDCH service account credentials from {}".format(filename) 

508 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

509 raise new_exc from caught_exc 

510 return credentials, info.get("project") 

511 

512 

513def get_api_key_credentials(key): 

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

515 from google.auth import api_key 

516 

517 return api_key.Credentials(key) 

518 

519 

520def _apply_quota_project_id(credentials, quota_project_id): 

521 if quota_project_id: 

522 credentials = credentials.with_quota_project(quota_project_id) 

523 else: 

524 credentials = credentials.with_quota_project_from_environment() 

525 

526 from google.oauth2 import credentials as authorized_user_credentials 

527 

528 if isinstance(credentials, authorized_user_credentials.Credentials) and ( 

529 not credentials.quota_project_id 

530 ): 

531 _warn_about_problematic_credentials(credentials) 

532 return credentials 

533 

534 

535def default(scopes=None, request=None, quota_project_id=None, default_scopes=None): 

536 """Gets the default credentials for the current environment. 

537 

538 `Application Default Credentials`_ provides an easy way to obtain 

539 credentials to call Google APIs for server-to-server or local applications. 

540 This function acquires credentials from the environment in the following 

541 order: 

542 

543 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set 

544 to the path of a valid service account JSON private key file, then it is 

545 loaded and returned. The project ID returned is the project ID defined 

546 in the service account file if available (some older files do not 

547 contain project ID information). 

548 

549 If the environment variable is set to the path of a valid external 

550 account JSON configuration file (workload identity federation), then the 

551 configuration file is used to determine and retrieve the external 

552 credentials from the current environment (AWS, Azure, etc). 

553 These will then be exchanged for Google access tokens via the Google STS 

554 endpoint. 

555 The project ID returned in this case is the one corresponding to the 

556 underlying workload identity pool resource if determinable. 

557 

558 If the environment variable is set to the path of a valid GDCH service 

559 account JSON file (`Google Distributed Cloud Hosted`_), then a GDCH 

560 credential will be returned. The project ID returned is the project 

561 specified in the JSON file. 

562 2. If the `Google Cloud SDK`_ is installed and has application default 

563 credentials set they are loaded and returned. 

564 

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

566 

567 gcloud auth application-default login 

568 

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

570 active project can be set using:: 

571 

572 gcloud config set project 

573 

574 3. If the application is running in the `App Engine standard environment`_ 

575 (first generation) then the credentials and project ID from the 

576 `App Identity Service`_ are used. 

577 4. If the application is running in `Compute Engine`_ or `Cloud Run`_ or 

578 the `App Engine flexible environment`_ or the `App Engine standard 

579 environment`_ (second generation) then the credentials and project ID 

580 are obtained from the `Metadata Service`_. 

581 5. If no credentials are found, 

582 :class:`~google.auth.exceptions.DefaultCredentialsError` will be raised. 

583 

584 .. _Application Default Credentials: https://developers.google.com\ 

585 /identity/protocols/application-default-credentials 

586 .. _Google Cloud SDK: https://cloud.google.com/sdk 

587 .. _App Engine standard environment: https://cloud.google.com/appengine 

588 .. _App Identity Service: https://cloud.google.com/appengine/docs/python\ 

589 /appidentity/ 

590 .. _Compute Engine: https://cloud.google.com/compute 

591 .. _App Engine flexible environment: https://cloud.google.com\ 

592 /appengine/flexible 

593 .. _Metadata Service: https://cloud.google.com/compute/docs\ 

594 /storing-retrieving-metadata 

595 .. _Cloud Run: https://cloud.google.com/run 

596 .. _Google Distributed Cloud Hosted: https://cloud.google.com/blog/topics\ 

597 /hybrid-cloud/announcing-google-distributed-cloud-edge-and-hosted 

598 

599 Example:: 

600 

601 import google.auth 

602 

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

604 

605 Args: 

606 scopes (Sequence[str]): The list of scopes for the credentials. If 

607 specified, the credentials will automatically be scoped if 

608 necessary. 

609 request (Optional[google.auth.transport.Request]): An object used to make 

610 HTTP requests. This is used to either detect whether the application 

611 is running on Compute Engine or to determine the associated project 

612 ID for a workload identity pool resource (external account 

613 credentials). If not specified, then it will either use the standard 

614 library http client to make requests for Compute Engine credentials 

615 or a google.auth.transport.requests.Request client for external 

616 account credentials. 

617 quota_project_id (Optional[str]): The project ID used for 

618 quota and billing. 

619 default_scopes (Optional[Sequence[str]]): Default scopes passed by a 

620 Google client library. Use 'scopes' for user-defined scopes. 

621 Returns: 

622 Tuple[~google.auth.credentials.Credentials, Optional[str]]: 

623 the current environment's credentials and project ID. Project ID 

624 may be None, which indicates that the Project ID could not be 

625 ascertained from the environment. 

626 

627 Raises: 

628 ~google.auth.exceptions.DefaultCredentialsError: 

629 If no credentials were found, or if the credentials found were 

630 invalid. 

631 """ 

632 from google.auth.credentials import with_scopes_if_required 

633 from google.auth.credentials import CredentialsWithQuotaProject 

634 

635 explicit_project_id = os.environ.get( 

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

637 ) 

638 

639 checkers = ( 

640 # Avoid passing scopes here to prevent passing scopes to user credentials. 

641 # with_scopes_if_required() below will ensure scopes/default scopes are 

642 # safely set on the returned credentials since requires_scopes will 

643 # guard against setting scopes on user credentials. 

644 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), 

645 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), 

646 _get_gae_credentials, 

647 lambda: _get_gce_credentials(request, quota_project_id=quota_project_id), 

648 ) 

649 

650 for checker in checkers: 

651 credentials, project_id = checker() 

652 if credentials is not None: 

653 credentials = with_scopes_if_required( 

654 credentials, scopes, default_scopes=default_scopes 

655 ) 

656 

657 effective_project_id = explicit_project_id or project_id 

658 

659 # For external account credentials, scopes are required to determine 

660 # the project ID. Try to get the project ID again if not yet 

661 # determined. 

662 if not effective_project_id and callable( 

663 getattr(credentials, "get_project_id", None) 

664 ): 

665 if request is None: 

666 import google.auth.transport.requests 

667 

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

669 effective_project_id = credentials.get_project_id(request=request) 

670 

671 if quota_project_id and isinstance( 

672 credentials, CredentialsWithQuotaProject 

673 ): 

674 credentials = credentials.with_quota_project(quota_project_id) 

675 

676 if not effective_project_id: 

677 _LOGGER.warning( 

678 "No project ID could be determined. Consider running " 

679 "`gcloud config set project` or setting the %s " 

680 "environment variable", 

681 environment_vars.PROJECT, 

682 ) 

683 return credentials, effective_project_id 

684 

685 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)