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

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

221 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 

241 if not project_id: 

242 project_id = _cloud_sdk.get_project_id() 

243 

244 return credentials, project_id 

245 

246 

247def _get_explicit_environ_credentials(quota_project_id=None): 

248 """Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment 

249 variable.""" 

250 from google.auth import _cloud_sdk 

251 

252 cloud_sdk_adc_path = _cloud_sdk.get_application_default_credentials_path() 

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

254 

255 _LOGGER.debug( 

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

257 ) 

258 

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

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

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

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

263 _LOGGER.debug( 

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

265 explicit_file, 

266 ) 

267 return _get_gcloud_sdk_credentials(quota_project_id=quota_project_id) 

268 

269 if explicit_file is not None: 

270 credentials, project_id = load_credentials_from_file( 

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

272 ) 

273 

274 return credentials, project_id 

275 

276 else: 

277 return None, None 

278 

279 

280def _get_gae_credentials(): 

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

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

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

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

285 return None, None 

286 

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

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

289 try: 

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

291 import google.auth.app_engine as app_engine 

292 except ImportError: 

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

294 return None, None 

295 

296 try: 

297 credentials = app_engine.Credentials() 

298 project_id = app_engine.get_project_id() 

299 return credentials, project_id 

300 except EnvironmentError: 

301 _LOGGER.debug( 

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

303 ) 

304 return None, None 

305 

306 

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

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

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

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

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

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

313 

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

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

316 try: 

317 from google.auth import compute_engine 

318 from google.auth.compute_engine import _metadata 

319 except ImportError: 

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

321 return None, None 

322 

323 if request is None: 

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

325 

326 if _metadata.is_on_gce(request=request): 

327 # Get the project ID. 

328 try: 

329 project_id = _metadata.get_project_id(request=request) 

330 except exceptions.TransportError: 

331 project_id = None 

332 

333 cred = compute_engine.Credentials() 

334 cred = _apply_quota_project_id(cred, quota_project_id) 

335 

336 return cred, project_id 

337 else: 

338 _LOGGER.warning( 

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

340 ) 

341 return None, None 

342 

343 

344def _get_external_account_credentials( 

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

346): 

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

348 

349 The credentials information must correspond to a supported external account 

350 credentials. 

351 

352 Args: 

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

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

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

356 specified, the credentials will automatically be scoped if 

357 necessary. 

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

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

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

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

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

363 If not specified, then it will use a 

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

365 

366 Returns: 

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

368 credentials and the project ID. External account credentials project 

369 IDs may not always be determined. 

370 

371 Raises: 

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

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

374 """ 

375 # There are currently 3 types of external_account credentials. 

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

377 # Check if configuration corresponds to an AWS credentials. 

378 from google.auth import aws 

379 

380 credentials = aws.Credentials.from_info( 

381 info, scopes=scopes, default_scopes=default_scopes 

382 ) 

383 elif ( 

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

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

386 ): 

387 from google.auth import pluggable 

388 

389 credentials = pluggable.Credentials.from_info( 

390 info, scopes=scopes, default_scopes=default_scopes 

391 ) 

392 else: 

393 try: 

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

395 from google.auth import identity_pool 

396 

397 credentials = identity_pool.Credentials.from_info( 

398 info, scopes=scopes, default_scopes=default_scopes 

399 ) 

400 except ValueError: 

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

402 # supported external_account credentials, raise an error. 

403 raise exceptions.DefaultCredentialsError( 

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

405 ) 

406 if request is None: 

407 import google.auth.transport.requests 

408 

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

410 

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

412 

413 

414def _get_external_account_authorized_user_credentials( 

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

416): 

417 try: 

418 from google.auth import external_account_authorized_user 

419 

420 credentials = external_account_authorized_user.Credentials.from_info(info) 

421 except ValueError: 

422 raise exceptions.DefaultCredentialsError( 

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

424 filename 

425 ) 

426 ) 

427 

428 return credentials, None 

429 

430 

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

432 from google.oauth2 import credentials 

433 

434 try: 

435 credentials = credentials.Credentials.from_authorized_user_info( 

436 info, scopes=scopes 

437 ) 

438 except ValueError as caught_exc: 

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

440 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

441 raise new_exc from caught_exc 

442 return credentials, None 

443 

444 

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

446 from google.oauth2 import service_account 

447 

448 try: 

449 credentials = service_account.Credentials.from_service_account_info( 

450 info, scopes=scopes, default_scopes=default_scopes 

451 ) 

452 except ValueError as caught_exc: 

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

454 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

455 raise new_exc from caught_exc 

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

457 

458 

459def _get_impersonated_service_account_credentials(filename, info, scopes): 

460 from google.auth import impersonated_credentials 

461 

462 try: 

463 source_credentials_info = info.get("source_credentials") 

464 source_credentials_type = source_credentials_info.get("type") 

465 if source_credentials_type == _AUTHORIZED_USER_TYPE: 

466 source_credentials, _ = _get_authorized_user_credentials( 

467 filename, source_credentials_info 

468 ) 

469 elif source_credentials_type == _SERVICE_ACCOUNT_TYPE: 

470 source_credentials, _ = _get_service_account_credentials( 

471 filename, source_credentials_info 

472 ) 

473 else: 

474 raise exceptions.InvalidType( 

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

476 source_credentials_type 

477 ) 

478 ) 

479 impersonation_url = info.get("service_account_impersonation_url") 

480 start_index = impersonation_url.rfind("/") 

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

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

483 raise exceptions.InvalidValue( 

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

485 ) 

486 target_principal = impersonation_url[start_index + 1 : end_index] 

487 delegates = info.get("delegates") 

488 quota_project_id = info.get("quota_project_id") 

489 credentials = impersonated_credentials.Credentials( 

490 source_credentials, 

491 target_principal, 

492 scopes, 

493 delegates, 

494 quota_project_id=quota_project_id, 

495 ) 

496 except ValueError as caught_exc: 

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

498 filename 

499 ) 

500 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

501 raise new_exc from caught_exc 

502 return credentials, None 

503 

504 

505def _get_gdch_service_account_credentials(filename, info): 

506 from google.oauth2 import gdch_credentials 

507 

508 try: 

509 credentials = gdch_credentials.ServiceAccountCredentials.from_service_account_info( 

510 info 

511 ) 

512 except ValueError as caught_exc: 

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

514 new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) 

515 raise new_exc from caught_exc 

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

517 

518 

519def get_api_key_credentials(key): 

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

521 from google.auth import api_key 

522 

523 return api_key.Credentials(key) 

524 

525 

526def _apply_quota_project_id(credentials, quota_project_id): 

527 if quota_project_id: 

528 credentials = credentials.with_quota_project(quota_project_id) 

529 else: 

530 credentials = credentials.with_quota_project_from_environment() 

531 

532 from google.oauth2 import credentials as authorized_user_credentials 

533 

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

535 not credentials.quota_project_id 

536 ): 

537 _warn_about_problematic_credentials(credentials) 

538 return credentials 

539 

540 

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

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

543 

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

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

546 This function acquires credentials from the environment in the following 

547 order: 

548 

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

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

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

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

553 contain project ID information). 

554 

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

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

557 configuration file is used to determine and retrieve the external 

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

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

560 endpoint. 

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

562 underlying workload identity pool resource if determinable. 

563 

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

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

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

567 specified in the JSON file. 

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

569 credentials set they are loaded and returned. 

570 

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

572 

573 gcloud auth application-default login 

574 

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

576 active project can be set using:: 

577 

578 gcloud config set project 

579 

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

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

582 `App Identity Service`_ are used. 

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

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

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

586 are obtained from the `Metadata Service`_. 

587 5. If no credentials are found, 

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

589 

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

591 /identity/protocols/application-default-credentials 

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

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

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

595 /appidentity/ 

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

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

598 /appengine/flexible 

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

600 /storing-retrieving-metadata 

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

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

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

604 

605 Example:: 

606 

607 import google.auth 

608 

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

610 

611 Args: 

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

613 specified, the credentials will automatically be scoped if 

614 necessary. 

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

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

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

618 ID for a workload identity pool resource (external account 

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

620 library http client to make requests for Compute Engine credentials 

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

622 account credentials. 

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

624 quota and billing. 

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

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

627 Returns: 

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

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

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

631 ascertained from the environment. 

632 

633 Raises: 

634 ~google.auth.exceptions.DefaultCredentialsError: 

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

636 invalid. 

637 """ 

638 from google.auth.credentials import with_scopes_if_required 

639 from google.auth.credentials import CredentialsWithQuotaProject 

640 

641 explicit_project_id = os.environ.get( 

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

643 ) 

644 

645 checkers = ( 

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

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

648 # safely set on the returned credentials since requires_scopes will 

649 # guard against setting scopes on user credentials. 

650 lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), 

651 lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), 

652 _get_gae_credentials, 

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

654 ) 

655 

656 for checker in checkers: 

657 credentials, project_id = checker() 

658 if credentials is not None: 

659 credentials = with_scopes_if_required( 

660 credentials, scopes, default_scopes=default_scopes 

661 ) 

662 

663 effective_project_id = explicit_project_id or project_id 

664 

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

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

667 # determined. 

668 if not effective_project_id and callable( 

669 getattr(credentials, "get_project_id", None) 

670 ): 

671 if request is None: 

672 import google.auth.transport.requests 

673 

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

675 effective_project_id = credentials.get_project_id(request=request) 

676 

677 if quota_project_id and isinstance( 

678 credentials, CredentialsWithQuotaProject 

679 ): 

680 credentials = credentials.with_quota_project(quota_project_id) 

681 

682 if not effective_project_id: 

683 _LOGGER.warning( 

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

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

686 "environment variable", 

687 environment_vars.PROJECT, 

688 ) 

689 return credentials, effective_project_id 

690 

691 raise exceptions.DefaultCredentialsError(_CLOUD_SDK_MISSING_CREDENTIALS)