Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/google/auth/_default.py: 16%

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

225 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 Args: 

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

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

91 specified, the credentials will automatically be scoped if 

92 necessary 

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

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

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

96 quota and billing. 

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

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

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

100 If not specified, then it will use a 

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

102 

103 Returns: 

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

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

106 have the project ID information. External account credentials project 

107 IDs may not always be determined. 

108 

109 Raises: 

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

111 wrong format or is missing. 

112 """ 

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

114 raise exceptions.DefaultCredentialsError( 

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

116 ) 

117 

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

119 try: 

120 info = json.load(file_obj) 

121 except ValueError as caught_exc: 

122 new_exc = exceptions.DefaultCredentialsError( 

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

124 ) 

125 raise new_exc from caught_exc 

126 return _load_credentials_from_info( 

127 filename, info, scopes, default_scopes, quota_project_id, request 

128 ) 

129 

130 

131def load_credentials_from_dict( 

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

133): 

134 """Loads Google credentials from a dict. 

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 Args: 

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

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

143 specified, the credentials will automatically be scoped if 

144 necessary 

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

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

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

148 quota and billing. 

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

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

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

152 If not specified, then it will use a 

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

154 

155 Returns: 

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

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

158 have the project ID information. External account credentials project 

159 IDs may not always be determined. 

160 

161 Raises: 

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

163 wrong format or is missing. 

164 """ 

165 if not isinstance(info, dict): 

166 raise exceptions.DefaultCredentialsError( 

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

168 ) 

169 

170 return _load_credentials_from_info( 

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

172 ) 

173 

174 

175def _load_credentials_from_info( 

176 filename, info, scopes, default_scopes, quota_project_id, request 

177): 

178 from google.auth.credentials import CredentialsWithQuotaProject 

179 

180 credential_type = info.get("type") 

181 

182 if credential_type == _AUTHORIZED_USER_TYPE: 

183 credentials, project_id = _get_authorized_user_credentials( 

184 filename, info, scopes 

185 ) 

186 

187 elif credential_type == _SERVICE_ACCOUNT_TYPE: 

188 credentials, project_id = _get_service_account_credentials( 

189 filename, info, scopes, default_scopes 

190 ) 

191 

192 elif credential_type == _EXTERNAL_ACCOUNT_TYPE: 

193 credentials, project_id = _get_external_account_credentials( 

194 info, 

195 filename, 

196 scopes=scopes, 

197 default_scopes=default_scopes, 

198 request=request, 

199 ) 

200 

201 elif credential_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE: 

202 credentials, project_id = _get_external_account_authorized_user_credentials( 

203 filename, info, request 

204 ) 

205 

206 elif credential_type == _IMPERSONATED_SERVICE_ACCOUNT_TYPE: 

207 credentials, project_id = _get_impersonated_service_account_credentials( 

208 filename, info, scopes 

209 ) 

210 elif credential_type == _GDCH_SERVICE_ACCOUNT_TYPE: 

211 credentials, project_id = _get_gdch_service_account_credentials(filename, info) 

212 else: 

213 raise exceptions.DefaultCredentialsError( 

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

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

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

217 ) 

218 ) 

219 if isinstance(credentials, CredentialsWithQuotaProject): 

220 credentials = _apply_quota_project_id(credentials, quota_project_id) 

221 return credentials, project_id 

222 

223 

224def _get_gcloud_sdk_credentials(quota_project_id=None): 

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

226 from google.auth import _cloud_sdk 

227 

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

229 

230 # Check if application default credentials exist. 

231 credentials_filename = _cloud_sdk.get_application_default_credentials_path() 

232 

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

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

235 return None, None 

236 

237 credentials, project_id = load_credentials_from_file( 

238 credentials_filename, quota_project_id=quota_project_id 

239 ) 

240 credentials._cred_file_path = credentials_filename 

241 

242 if not project_id: 

243 project_id = _cloud_sdk.get_project_id() 

244 

245 return credentials, project_id 

246 

247 

248def _get_explicit_environ_credentials(quota_project_id=None): 

249 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment 

250 variable.""" 

251 from google.auth import _cloud_sdk 

252 

253 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() 

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

255 

256 _LOGGER.debug( 

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

258 ) 

259 

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

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

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

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

264 _LOGGER.debug( 

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

266 explicit_file, 

267 ) 

268 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id) 

269 

270 if explicit_file is not None: 

271 credentials, project_id = load_credentials_from_file( 

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

273 ) 

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

275 

276 return credentials, project_id 

277 

278 else: 

279 return None, None 

280 

281 

282def _get_gae_credentials(): 

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

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

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

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

287 return None, None 

288 

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

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

291 try: 

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

293 import google.auth.app_engine as app_engine 

294 except ImportError: 

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

296 return None, None 

297 

298 try: 

299 credentials = app_engine.Credentials() 

300 project_id = app_engine.get_project_id() 

301 return credentials, project_id 

302 except EnvironmentError: 

303 _LOGGER.debug( 

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

305 ) 

306 return None, None 

307 

308 

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

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

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

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

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

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

315 

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

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

318 try: 

319 from google.auth import compute_engine 

320 from google.auth.compute_engine import _metadata 

321 except ImportError: 

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

323 return None, None 

324 

325 if request is None: 

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

327 

328 if _metadata.is_on_gce(request=request): 

329 # Get the project ID. 

330 try: 

331 project_id = _metadata.get_project_id(request=request) 

332 except exceptions.TransportError: 

333 project_id = None 

334 

335 cred = compute_engine.Credentials() 

336 cred = _apply_quota_project_id(cred, quota_project_id) 

337 

338 return cred, project_id 

339 else: 

340 _LOGGER.warning( 

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

342 ) 

343 return None, None 

344 

345 

346def _get_external_account_credentials( 

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

348): 

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

350 

351 The credentials information must correspond to a supported external account 

352 credentials. 

353 

354 Args: 

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

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

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

358 specified, the credentials will automatically be scoped if 

359 necessary. 

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

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

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

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

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

365 If not specified, then it will use a 

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

367 

368 Returns: 

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

370 credentials and the project ID. External account credentials project 

371 IDs may not always be determined. 

372 

373 Raises: 

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

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

376 """ 

377 # There are currently 3 types of external_account credentials. 

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

379 # Check if configuration corresponds to an AWS credentials. 

380 from google.auth import aws 

381 

382 credentials = aws.Credentials.from_info( 

383 info, scopes=scopes, default_scopes=default_scopes 

384 ) 

385 elif ( 

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

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

388 ): 

389 from google.auth import pluggable 

390 

391 credentials = pluggable.Credentials.from_info( 

392 info, scopes=scopes, default_scopes=default_scopes 

393 ) 

394 else: 

395 try: 

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

397 from google.auth import identity_pool 

398 

399 credentials = identity_pool.Credentials.from_info( 

400 info, scopes=scopes, default_scopes=default_scopes 

401 ) 

402 except ValueError: 

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

404 # supported external_account credentials, raise an error. 

405 raise exceptions.DefaultCredentialsError( 

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

407 ) 

408 if request is None: 

409 import google.auth.transport.requests 

410 

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

412 

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

414 

415 

416def _get_external_account_authorized_user_credentials( 

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

418): 

419 try: 

420 from google.auth import external_account_authorized_user 

421 

422 credentials = external_account_authorized_user.Credentials.from_info(info) 

423 except ValueError: 

424 raise exceptions.DefaultCredentialsError( 

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

426 filename 

427 ) 

428 ) 

429 

430 return credentials, None 

431 

432 

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

434 from google.oauth2 import credentials 

435 

436 try: 

437 credentials = credentials.Credentials.from_authorized_user_info( 

438 info, scopes=scopes 

439 ) 

440 except ValueError as caught_exc: 

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

442 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

443 raise new_exc from caught_exc 

444 return credentials, None 

445 

446 

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

448 from google.oauth2 import service_account 

449 

450 try: 

451 credentials = service_account.Credentials.from_service_account_info( 

452 info, scopes=scopes, default_scopes=default_scopes 

453 ) 

454 except ValueError as caught_exc: 

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

456 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

457 raise new_exc from caught_exc 

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

459 

460 

461def _get_impersonated_service_account_credentials(filename, info, scopes): 

462 from google.auth import impersonated_credentials 

463 

464 try: 

465 source_credentials_info = info.get("source_credentials") 

466 source_credentials_type = source_credentials_info.get("type") 

467 if source_credentials_type == _AUTHORIZED_USER_TYPE: 

468 source_credentials, _ = _get_authorized_user_credentials( 

469 filename, source_credentials_info 

470 ) 

471 elif source_credentials_type == _SERVICE_ACCOUNT_TYPE: 

472 source_credentials, _ = _get_service_account_credentials( 

473 filename, source_credentials_info 

474 ) 

475 elif source_credentials_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE: 

476 source_credentials, _ = _get_external_account_authorized_user_credentials( 

477 filename, source_credentials_info 

478 ) 

479 else: 

480 raise exceptions.InvalidType( 

481 "source credential of type {} is not supported.".format( 

482 source_credentials_type 

483 ) 

484 ) 

485 impersonation_url = info.get("service_account_impersonation_url") 

486 start_index = impersonation_url.rfind("/") 

487 end_index = impersonation_url.find(":generateAccessToken") 

488 if start_index == -1 or end_index == -1 or start_index > end_index: 

489 raise exceptions.InvalidValue( 

490 "Cannot extract target principal from {}".format(impersonation_url) 

491 ) 

492 target_principal = impersonation_url[start_index + 1 : end_index] 

493 delegates = info.get("delegates") 

494 quota_project_id = info.get("quota_project_id") 

495 credentials = impersonated_credentials.Credentials( 

496 source_credentials, 

497 target_principal, 

498 scopes, 

499 delegates, 

500 quota_project_id=quota_project_id, 

501 ) 

502 except ValueError as caught_exc: 

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

504 filename 

505 ) 

506 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

507 raise new_exc from caught_exc 

508 return credentials, None 

509 

510 

511def _get_gdch_service_account_credentials(filename, info): 

512 from google.oauth2 import gdch_credentials 

513 

514 try: 

515 credentials = gdch_credentials.ServiceAccountCredentials.from_service_account_info( 

516 info 

517 ) 

518 except ValueError as caught_exc: 

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

520 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

521 raise new_exc from caught_exc 

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

523 

524 

525def get_api_key_credentials(key): 

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

527 from google.auth import api_key 

528 

529 return api_key.Credentials(key) 

530 

531 

532def _apply_quota_project_id(credentials, quota_project_id): 

533 if quota_project_id: 

534 credentials = credentials.with_quota_project(quota_project_id) 

535 else: 

536 credentials = credentials.with_quota_project_from_environment() 

537 

538 from google.oauth2 import credentials as authorized_user_credentials 

539 

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

541 not credentials.quota_project_id 

542 ): 

543 _warn_about_problematic_credentials(credentials) 

544 return credentials 

545 

546 

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

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

549 

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

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

552 This function acquires credentials from the environment in the following 

553 order: 

554 

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

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

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

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

559 contain project ID information). 

560 

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

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

563 configuration file is used to determine and retrieve the external 

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

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

566 endpoint. 

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

568 underlying workload identity pool resource if determinable. 

569 

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

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

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

573 specified in the JSON file. 

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

575 credentials set they are loaded and returned. 

576 

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

578 

579 gcloud auth application-default login 

580 

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

582 active project can be set using:: 

583 

584 gcloud config set project 

585 

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

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

588 `App Identity Service`_ are used. 

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

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

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

592 are obtained from the `Metadata Service`_. 

593 5. If no credentials are found, 

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

595 

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

597 /identity/protocols/application-default-credentials 

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

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

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

601 /appidentity/ 

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

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

604 /appengine/flexible 

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

606 /storing-retrieving-metadata 

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

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

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

610 

611 Example:: 

612 

613 import google.auth 

614 

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

616 

617 Args: 

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

619 specified, the credentials will automatically be scoped if 

620 necessary. 

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

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

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

624 ID for a workload identity pool resource (external account 

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

626 library http client to make requests for Compute Engine credentials 

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

628 account credentials. 

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

630 quota and billing. 

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

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

633 Returns: 

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

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

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

637 ascertained from the environment. 

638 

639 Raises: 

640 ~google.auth.exceptions.DefaultCredentialsError: 

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

642 invalid. 

643 """ 

644 from google.auth.credentials import with_scopes_if_required 

645 from google.auth.credentials import CredentialsWithQuotaProject 

646 

647 explicit_project_id = os.environ.get( 

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

649 ) 

650 

651 checkers = ( 

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

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

654 # safely set on the returned credentials since requires_scopes will 

655 # guard against setting scopes on user credentials. 

656 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), 

657 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), 

658 _get_gae_credentials, 

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

660 ) 

661 

662 for checker in checkers: 

663 credentials, project_id = checker() 

664 if credentials is not None: 

665 credentials = with_scopes_if_required( 

666 credentials, scopes, default_scopes=default_scopes 

667 ) 

668 

669 effective_project_id = explicit_project_id or project_id 

670 

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

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

673 # determined. 

674 if not effective_project_id and callable( 

675 getattr(credentials, "get_project_id", None) 

676 ): 

677 if request is None: 

678 import google.auth.transport.requests 

679 

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

681 effective_project_id = credentials.get_project_id(request=request) 

682 

683 if quota_project_id and isinstance( 

684 credentials, CredentialsWithQuotaProject 

685 ): 

686 credentials = credentials.with_quota_project(quota_project_id) 

687 

688 if not effective_project_id: 

689 _LOGGER.warning( 

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

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

692 "environment variable", 

693 environment_vars.PROJECT, 

694 ) 

695 return credentials, effective_project_id 

696 

697 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)