google-auth 2.56.0__tar.gz → 2.56.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {google_auth-2.56.0/google_auth.egg-info → google_auth-2.56.2}/PKG-INFO +1 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_agent_identity_utils.py +90 -62
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/compute_engine/_metadata.py +3 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/impersonated_credentials.py +5 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/jwt.py +11 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/_mtls_helper.py +31 -59
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/mtls.py +9 -15
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/requests.py +70 -4
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/urllib3.py +12 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/version.py +1 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/service_account.py +5 -1
- {google_auth-2.56.0 → google_auth-2.56.2/google_auth.egg-info}/PKG-INFO +1 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/compute_engine/test__metadata.py +5 -1
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/compute_engine/test_credentials.py +117 -51
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_service_account.py +4 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_agent_identity_utils.py +203 -108
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_impersonated_credentials.py +4 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_jwt.py +25 -2
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test__mtls_helper.py +94 -101
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test_grpc.py +12 -7
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test_mtls.py +41 -40
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test_requests.py +135 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test_urllib3.py +57 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/LICENSE +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/MANIFEST.in +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/README.rst +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_cache.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_cloud_sdk.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_credentials_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_credentials_base.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_default.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_default_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_exponential_backoff.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_helpers.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_jwt_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_oauth2client.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_refresh_worker.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_regional_access_boundary_utils.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/_service_account_info.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/_helpers.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/transport/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/transport/aiohttp.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/transport/mtls.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aio/transport/sessions.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/api_key.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/app_engine.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/aws.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/compute_engine/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/compute_engine/_mtls.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/compute_engine/credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/_cryptography_rsa.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/_helpers.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/_python_rsa.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/base.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/es.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/es256.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/crypt/rsa.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/downscoped.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/environment_vars.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/exceptions.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/external_account.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/external_account_authorized_user.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/iam.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/identity_pool.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/metrics.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/pluggable.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/py.typed +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/_aiohttp_requests.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/_custom_tls_signer.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/_http_client.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/_requests_base.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/auth/transport/grpc.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/_client.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/_client_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/_credentials_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/_id_token_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/_reauth_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/_service_account_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/challenges.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/gdch_credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/id_token.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/py.typed +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/reauth.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/sts.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/utils.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/webauthn_handler.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/webauthn_handler_factory.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google/oauth2/webauthn_types.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google_auth.egg-info/SOURCES.txt +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google_auth.egg-info/dependency_links.txt +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google_auth.egg-info/requires.txt +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/google_auth.egg-info/top_level.txt +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/setup.cfg +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/setup.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/aio/test__helpers.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/compute_engine/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/compute_engine/data/smbios_product_name +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/compute_engine/data/smbios_product_name_non_google +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/compute_engine/test__mtls.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/conftest.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/test__cryptography_rsa.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/test__python_rsa.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/test_crypt.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/test_es.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/test_es256.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/crypt/test_rsa.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/authorized_user.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/authorized_user_cloud_sdk.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/authorized_user_cloud_sdk_with_quota_project_id.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/authorized_user_with_rapt_token.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/client_secrets.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/context_aware_metadata.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/enterprise_cert_invalid.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/enterprise_cert_valid.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/enterprise_cert_valid_provider.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es256_privatekey.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es256_public_cert.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es256_publickey.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es256_service_account.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es384_privatekey.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es384_public_cert.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es384_publickey.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/es384_service_account.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/external_account_authorized_user.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/external_account_authorized_user_non_gdu.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/external_subject_token.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/external_subject_token.txt +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/gdch_service_account.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/impersonated_service_account_authorized_user_source.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/impersonated_service_account_external_account_authorized_user_source.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/impersonated_service_account_service_account_source.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/impersonated_service_account_with_quota_project.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/old_oauth_credentials_py3.pickle +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/other_cert.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/pem_from_pkcs12.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/privatekey.p12 +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/privatekey.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/privatekey.pub +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/public_cert.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/service_account.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/service_account_non_gdu.json +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/trust_chain_with_leaf.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/trust_chain_without_leaf.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/data/trust_chain_wrong_order.pem +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test__client.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_challenges.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_gdch_credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_id_token.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_reauth.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_sts.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_utils.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_webauthn_handler.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_webauthn_handler_factory.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/oauth2/test_webauthn_types.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__cache.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__cloud_sdk.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__default.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__exponential_backoff.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__helpers.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__oauth2client.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__refresh_worker.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__regional_access_boundary_utils.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test__service_account_info.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_api_key.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_app_engine.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_aws.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_credentials.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_credentials_async.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_downscoped.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_exceptions.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_external_account.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_external_account_authorized_user.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_iam.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_identity_pool.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_metrics.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_packaging.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/test_pluggable.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/__init__.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/aio/conftest.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/aio/test_aiohttp.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/aio/test_sessions.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/aio/test_sessions_mtls.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/aioresponses_compat.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/compliance.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test__custom_tls_signer.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test__http_client.py +0 -0
- {google_auth-2.56.0 → google_auth-2.56.2}/tests/transport/test_aio_mtls_helper.py +0 -0
|
@@ -67,93 +67,88 @@ def _is_certificate_file_ready(path):
|
|
|
67
67
|
st = os.stat(path)
|
|
68
68
|
return stat.S_ISREG(st.st_mode) and st.st_size > 0
|
|
69
69
|
except PermissionError:
|
|
70
|
-
# Propagate PermissionError to let caller handle it (
|
|
70
|
+
# Propagate PermissionError to let caller handle it (e.g., return early or fallback)
|
|
71
71
|
raise
|
|
72
72
|
except OSError:
|
|
73
73
|
return False
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def get_agent_identity_certificate_path():
|
|
77
|
-
"""Gets the certificate path from the certificate config file.
|
|
77
|
+
"""Gets the agent certificate path from the certificate config file.
|
|
78
78
|
|
|
79
79
|
The path to the certificate config file is read from the
|
|
80
80
|
GOOGLE_API_CERTIFICATE_CONFIG environment variable. This function
|
|
81
|
-
|
|
81
|
+
can optionally trigger polling to handle cases where the environment
|
|
82
82
|
variable is set before the files are available on the filesystem.
|
|
83
83
|
|
|
84
84
|
Returns:
|
|
85
|
-
str: The path to the
|
|
85
|
+
Optional[str]: The path to the agent's certificate file, or None if unavailable.
|
|
86
86
|
|
|
87
87
|
Raises:
|
|
88
88
|
google.auth.exceptions.RefreshError: If the certificate config file
|
|
89
89
|
or the certificate file cannot be found after retries.
|
|
90
90
|
"""
|
|
91
|
-
import json
|
|
92
|
-
|
|
93
91
|
cert_config_path = os.environ.get(environment_vars.GOOGLE_API_CERTIFICATE_CONFIG)
|
|
94
92
|
|
|
95
|
-
|
|
93
|
+
if not cert_config_path:
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
# We trigger polling only if the config path points to the well-known directory.
|
|
97
|
+
# Cloud Run dynamically generates these files in this directory, and both the
|
|
98
|
+
# config file and the certificate file may experience a brief startup latency.
|
|
99
|
+
# For all other paths, we return early to avoid introducing unnecessary startup
|
|
100
|
+
# delays.
|
|
96
101
|
well_known_dir = os.path.dirname(_WELL_KNOWN_CERT_PATH)
|
|
97
|
-
|
|
102
|
+
try:
|
|
103
|
+
abs_cert_path = os.path.abspath(cert_config_path)
|
|
104
|
+
abs_well_known_dir = os.path.abspath(well_known_dir)
|
|
105
|
+
should_poll = (
|
|
106
|
+
os.path.commonpath([abs_well_known_dir, abs_cert_path])
|
|
107
|
+
== abs_well_known_dir
|
|
108
|
+
)
|
|
109
|
+
except ValueError:
|
|
110
|
+
should_poll = False
|
|
98
111
|
|
|
99
|
-
|
|
100
|
-
if not cert_config_path and not has_well_known_dir:
|
|
101
|
-
return None
|
|
112
|
+
return _get_cert_path_with_optional_polling(cert_config_path, should_poll)
|
|
102
113
|
|
|
103
|
-
# If ECP config path is specified but does not exist, and we are on a workstation, fail-fast immediately.
|
|
104
|
-
if (
|
|
105
|
-
cert_config_path
|
|
106
|
-
and not has_well_known_dir
|
|
107
|
-
and not os.path.exists(cert_config_path)
|
|
108
|
-
):
|
|
109
|
-
return None
|
|
110
114
|
|
|
115
|
+
def _get_cert_path_with_optional_polling(cert_config_path, should_poll):
|
|
116
|
+
"""Gets the certificate path, optionally polling until it is ready.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
cert_config_path (str): The path to the certificate configuration file.
|
|
120
|
+
should_poll (bool): If True, the function will poll for the file and
|
|
121
|
+
certificate to be ready. If False, it will check only once and
|
|
122
|
+
return early if they are not immediately available.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
str: The path to the certificate file, or None if unavailable.
|
|
126
|
+
|
|
127
|
+
Raises:
|
|
128
|
+
google.auth.exceptions.RefreshError: If the certificate config file
|
|
129
|
+
or the certificate file cannot be found after retries.
|
|
130
|
+
"""
|
|
111
131
|
has_logged_config_warning = False
|
|
112
132
|
has_logged_cert_warning = False
|
|
113
133
|
|
|
114
134
|
for interval in _POLLING_INTERVALS:
|
|
115
135
|
try:
|
|
116
|
-
|
|
117
|
-
if cert_config_path:
|
|
118
|
-
with open(cert_config_path, "r") as f:
|
|
119
|
-
cert_config = json.load(f)
|
|
120
|
-
|
|
121
|
-
cert_configs = (
|
|
122
|
-
cert_config.get("cert_configs")
|
|
123
|
-
if isinstance(cert_config, dict)
|
|
124
|
-
else None
|
|
125
|
-
)
|
|
126
|
-
workload_config = (
|
|
127
|
-
cert_configs.get("workload")
|
|
128
|
-
if isinstance(cert_configs, dict)
|
|
129
|
-
else None
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
not isinstance(workload_config, dict)
|
|
134
|
-
or "cert_path" not in workload_config
|
|
135
|
-
):
|
|
136
|
-
return None
|
|
137
|
-
|
|
138
|
-
cert_path = workload_config["cert_path"]
|
|
139
|
-
if _is_certificate_file_ready(cert_path):
|
|
140
|
-
return cert_path
|
|
136
|
+
cert_path = _parse_cert_path_from_config(cert_config_path)
|
|
141
137
|
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
if cert_path is None:
|
|
139
|
+
return None
|
|
144
140
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if _is_certificate_file_ready(_WELL_KNOWN_CERT_PATH):
|
|
148
|
-
return _WELL_KNOWN_CERT_PATH
|
|
141
|
+
if _is_certificate_file_ready(cert_path):
|
|
142
|
+
return cert_path
|
|
149
143
|
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
# The config was parsed, but the cert file is not ready yet
|
|
145
|
+
if not should_poll:
|
|
146
|
+
# If polling is disabled, return early.
|
|
147
|
+
return None
|
|
152
148
|
|
|
153
|
-
# Log a warning on the first failed attempt to load the certificate file
|
|
154
149
|
if not has_logged_cert_warning:
|
|
155
150
|
warnings.warn(
|
|
156
|
-
f"Certificate file not ready at {
|
|
151
|
+
f"Certificate file not ready at {cert_path}. Retrying until startup timeout (up to {_TOTAL_TIMEOUT} seconds total)..."
|
|
157
152
|
)
|
|
158
153
|
has_logged_cert_warning = True
|
|
159
154
|
|
|
@@ -164,25 +159,24 @@ def get_agent_identity_certificate_path():
|
|
|
164
159
|
)
|
|
165
160
|
return None
|
|
166
161
|
except (IOError, ValueError, KeyError) as e:
|
|
167
|
-
if
|
|
162
|
+
if os.path.exists(cert_config_path):
|
|
168
163
|
# If the file exists but has invalid JSON or is unreadable,
|
|
169
|
-
# we assume it is in its final format and
|
|
164
|
+
# we assume it is in its final format and return early (returning None).
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
if not should_poll:
|
|
168
|
+
# If polling is disabled, return early if the file doesn't exist.
|
|
170
169
|
return None
|
|
171
170
|
|
|
172
|
-
if not has_logged_config_warning
|
|
171
|
+
if not has_logged_config_warning:
|
|
173
172
|
warnings.warn(
|
|
174
173
|
f"Certificate config file not found or incomplete: {e} (from "
|
|
175
174
|
f"{environment_vars.GOOGLE_API_CERTIFICATE_CONFIG} environment variable). "
|
|
176
175
|
f"Retrying until startup timeout (up to {_TOTAL_TIMEOUT} seconds total)..."
|
|
177
176
|
)
|
|
178
177
|
has_logged_config_warning = True
|
|
179
|
-
pass
|
|
180
178
|
|
|
181
|
-
#
|
|
182
|
-
# 1. The config file is not found (the except block).
|
|
183
|
-
# 2. The config file/well-known path is found, but the certificate is not yet available.
|
|
184
|
-
# In both cases, we need to poll, so we sleep on every iteration
|
|
185
|
-
# that doesn't return a certificate.
|
|
179
|
+
# Sleep before the next polling attempt.
|
|
186
180
|
time.sleep(interval)
|
|
187
181
|
|
|
188
182
|
raise exceptions.RefreshError(
|
|
@@ -193,6 +187,40 @@ def get_agent_identity_certificate_path():
|
|
|
193
187
|
)
|
|
194
188
|
|
|
195
189
|
|
|
190
|
+
def _parse_cert_path_from_config(cert_config_path):
|
|
191
|
+
"""Reads the cert config file and returns the cert_path.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
cert_config_path (str): The path to the certificate configuration file.
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Optional[str]: The path to the certificate file, or None if not found
|
|
198
|
+
in the config.
|
|
199
|
+
|
|
200
|
+
Raises:
|
|
201
|
+
IOError: If the certificate config file cannot be read.
|
|
202
|
+
ValueError: If the certificate config file contains invalid JSON.
|
|
203
|
+
KeyError: If the certificate config file does not contain the
|
|
204
|
+
expected structure.
|
|
205
|
+
"""
|
|
206
|
+
import json
|
|
207
|
+
|
|
208
|
+
with open(cert_config_path, "r", encoding="utf-8") as f:
|
|
209
|
+
cert_config = json.load(f)
|
|
210
|
+
|
|
211
|
+
cert_configs = (
|
|
212
|
+
cert_config.get("cert_configs") if isinstance(cert_config, dict) else None
|
|
213
|
+
)
|
|
214
|
+
workload_config = (
|
|
215
|
+
cert_configs.get("workload") if isinstance(cert_configs, dict) else None
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
if not isinstance(workload_config, dict) or "cert_path" not in workload_config:
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
return workload_config["cert_path"]
|
|
222
|
+
|
|
223
|
+
|
|
196
224
|
def get_and_parse_agent_identity_certificate():
|
|
197
225
|
"""Gets and parses the agent identity certificate if not opted out.
|
|
198
226
|
|
|
@@ -38,7 +38,9 @@ from google.auth.compute_engine import _mtls
|
|
|
38
38
|
|
|
39
39
|
_LOGGER = logging.getLogger(__name__)
|
|
40
40
|
|
|
41
|
-
_SERVICE_ACCOUNT_EMAIL_PATTERN = re.compile(
|
|
41
|
+
_SERVICE_ACCOUNT_EMAIL_PATTERN = re.compile(
|
|
42
|
+
r"^[^@]+@[^@]+\.gserviceaccount\.com$", re.IGNORECASE
|
|
43
|
+
)
|
|
42
44
|
|
|
43
45
|
_GCE_DEFAULT_MDS_IP = "169.254.169.254"
|
|
44
46
|
_GCE_DEFAULT_HOST = "metadata.google.internal"
|
|
@@ -362,8 +362,12 @@ class Credentials(
|
|
|
362
362
|
|
|
363
363
|
Returns:
|
|
364
364
|
Optional[str]: The URL for the Regional Access Boundary lookup endpoint, or None
|
|
365
|
-
if the service account email is missing.
|
|
365
|
+
if the service account email is missing. Returns None if the subject is populated.
|
|
366
366
|
"""
|
|
367
|
+
if self._subject:
|
|
368
|
+
# RAB does not apply to Workspace User Accounts via Domain-wide Delegation.
|
|
369
|
+
return None
|
|
370
|
+
|
|
367
371
|
if not self.service_account_email:
|
|
368
372
|
_LOGGER.error(
|
|
369
373
|
"Service account email is required to build the Regional Access Boundary lookup URL for impersonated credentials."
|
|
@@ -585,7 +585,17 @@ class Credentials(
|
|
|
585
585
|
self.token, self.expiry = self._make_jwt()
|
|
586
586
|
|
|
587
587
|
def _build_regional_access_boundary_lookup_url(self, request=None):
|
|
588
|
-
"""Builds the lookup URL using the service account's email address.
|
|
588
|
+
"""Builds the lookup URL using the service account's email address.
|
|
589
|
+
|
|
590
|
+
Returns None if the subject is populated.
|
|
591
|
+
"""
|
|
592
|
+
# In jwt.Credentials, subject defaults to client_email (which is the issuer).
|
|
593
|
+
# We must check self._subject != self._issuer to correctly determine if
|
|
594
|
+
# Domain-Wide Delegation is active.
|
|
595
|
+
if self._subject and self._subject != self._issuer:
|
|
596
|
+
# RAB does not apply to Workspace User Accounts via Domain-wide Delegation.
|
|
597
|
+
return None
|
|
598
|
+
|
|
589
599
|
if not self.signer_email:
|
|
590
600
|
return None
|
|
591
601
|
|
|
@@ -26,6 +26,7 @@ import tempfile
|
|
|
26
26
|
from typing import cast, Generator, List, Optional, Tuple, Union
|
|
27
27
|
|
|
28
28
|
from google.auth import _agent_identity_utils
|
|
29
|
+
from google.auth import _cloud_sdk
|
|
29
30
|
from google.auth import environment_vars
|
|
30
31
|
from google.auth import exceptions
|
|
31
32
|
|
|
@@ -51,30 +52,10 @@ _KEY_REGEX = re.compile(
|
|
|
51
52
|
_LOGGER = logging.getLogger(__name__)
|
|
52
53
|
|
|
53
54
|
|
|
54
|
-
# A flag to track if we have already logged a warning about mTLS auto-enablement failures.
|
|
55
|
-
# This prevents log spam when client libraries create transports or session instances
|
|
56
|
-
# frequently within a single process.
|
|
57
|
-
_has_logged_mtls_warning = False
|
|
58
|
-
|
|
59
|
-
|
|
60
55
|
_PASSPHRASE_REGEX = re.compile(
|
|
61
56
|
b"-----BEGIN PASSPHRASE-----(.+)-----END PASSPHRASE-----", re.DOTALL
|
|
62
57
|
)
|
|
63
58
|
|
|
64
|
-
# Temporary patch to accomodate incorrect cert config in Cloud Run prod environment.
|
|
65
|
-
_WELL_KNOWN_CLOUD_RUN_CERT_PATH = (
|
|
66
|
-
"/var/run/secrets/workload-spiffe-credentials/certificates.pem"
|
|
67
|
-
)
|
|
68
|
-
_WELL_KNOWN_CLOUD_RUN_KEY_PATH = (
|
|
69
|
-
"/var/run/secrets/workload-spiffe-credentials/private_key.pem"
|
|
70
|
-
)
|
|
71
|
-
_INCORRECT_CLOUD_RUN_CERT_PATH = (
|
|
72
|
-
"/var/lib/volumes/certificate/workload-certificates/certificates.pem"
|
|
73
|
-
)
|
|
74
|
-
_INCORRECT_CLOUD_RUN_KEY_PATH = (
|
|
75
|
-
"/var/lib/volumes/certificate/workload-certificates/private_key.pem"
|
|
76
|
-
)
|
|
77
|
-
|
|
78
59
|
|
|
79
60
|
class _MemfdCreationError(OSError):
|
|
80
61
|
"""Raised when Linux in-memory virtual file creation (memfd) fails."""
|
|
@@ -436,10 +417,15 @@ def _get_cert_config_path(certificate_config_path=None, include_context_aware=Tr
|
|
|
436
417
|
The absolute path of the certificate config file, and None if the file does not exist.
|
|
437
418
|
"""
|
|
438
419
|
|
|
420
|
+
source = "function argument"
|
|
421
|
+
is_explicit = True
|
|
439
422
|
if certificate_config_path is None:
|
|
440
423
|
env_path = environ.get(environment_vars.GOOGLE_API_CERTIFICATE_CONFIG, None)
|
|
441
424
|
if env_path is not None and env_path != "":
|
|
442
425
|
certificate_config_path = env_path
|
|
426
|
+
source = (
|
|
427
|
+
f"environment variable {environment_vars.GOOGLE_API_CERTIFICATE_CONFIG}"
|
|
428
|
+
)
|
|
443
429
|
else:
|
|
444
430
|
env_path = environ.get(
|
|
445
431
|
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH,
|
|
@@ -447,11 +433,21 @@ def _get_cert_config_path(certificate_config_path=None, include_context_aware=Tr
|
|
|
447
433
|
)
|
|
448
434
|
if include_context_aware and env_path is not None and env_path != "":
|
|
449
435
|
certificate_config_path = env_path
|
|
436
|
+
source = f"environment variable {environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH}"
|
|
450
437
|
else:
|
|
451
|
-
certificate_config_path =
|
|
438
|
+
certificate_config_path = os.path.join(
|
|
439
|
+
_cloud_sdk.get_config_path(), "certificate_config.json"
|
|
440
|
+
)
|
|
441
|
+
is_explicit = False
|
|
452
442
|
|
|
453
443
|
certificate_config_path = path.expanduser(certificate_config_path)
|
|
454
444
|
if not path.exists(certificate_config_path):
|
|
445
|
+
if is_explicit:
|
|
446
|
+
_LOGGER.debug(
|
|
447
|
+
"Certificate configuration file explicitly specified via %s at %s does not exist",
|
|
448
|
+
source,
|
|
449
|
+
certificate_config_path,
|
|
450
|
+
)
|
|
455
451
|
return None
|
|
456
452
|
return certificate_config_path
|
|
457
453
|
|
|
@@ -489,25 +485,6 @@ def _get_workload_cert_and_key_paths(config_path, include_context_aware=True):
|
|
|
489
485
|
cert_path = workload["cert_path"]
|
|
490
486
|
key_path = workload["key_path"]
|
|
491
487
|
|
|
492
|
-
# == BEGIN Temporary Cloud Run PATCH ==
|
|
493
|
-
# See https://github.com/googleapis/google-auth-library-python/issues/1881
|
|
494
|
-
if (cert_path == _INCORRECT_CLOUD_RUN_CERT_PATH) and (
|
|
495
|
-
key_path == _INCORRECT_CLOUD_RUN_KEY_PATH
|
|
496
|
-
):
|
|
497
|
-
if not path.exists(cert_path) and not path.exists(key_path):
|
|
498
|
-
_LOGGER.debug(
|
|
499
|
-
"Applying Cloud Run certificate path patch. "
|
|
500
|
-
"Configured paths not found: %s, %s. "
|
|
501
|
-
"Using well-known paths: %s, %s",
|
|
502
|
-
cert_path,
|
|
503
|
-
key_path,
|
|
504
|
-
_WELL_KNOWN_CLOUD_RUN_CERT_PATH,
|
|
505
|
-
_WELL_KNOWN_CLOUD_RUN_KEY_PATH,
|
|
506
|
-
)
|
|
507
|
-
cert_path = _WELL_KNOWN_CLOUD_RUN_CERT_PATH
|
|
508
|
-
key_path = _WELL_KNOWN_CLOUD_RUN_KEY_PATH
|
|
509
|
-
# == END Temporary Cloud Run PATCH ==
|
|
510
|
-
|
|
511
488
|
return cert_path, key_path
|
|
512
489
|
|
|
513
490
|
|
|
@@ -755,36 +732,33 @@ def check_use_client_cert():
|
|
|
755
732
|
will default to False.
|
|
756
733
|
If GOOGLE_API_USE_CLIENT_CERTIFICATE is unset, the value will be inferred
|
|
757
734
|
as True (auto-enabled) if a workload config file exists (pointed at by
|
|
758
|
-
GOOGLE_API_CERTIFICATE_CONFIG
|
|
735
|
+
GOOGLE_API_CERTIFICATE_CONFIG or CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH,
|
|
736
|
+
or the default path like ~/.config/gcloud/certificate_config.json)
|
|
737
|
+
containing a "workload" section.
|
|
759
738
|
Otherwise, it returns False.
|
|
760
739
|
|
|
761
740
|
Returns:
|
|
762
741
|
bool: Whether the client certificate should be used for mTLS connection.
|
|
763
742
|
"""
|
|
764
|
-
global _has_logged_mtls_warning
|
|
765
743
|
env_override = _check_use_client_cert_env()
|
|
766
744
|
if env_override is not None:
|
|
767
745
|
return env_override
|
|
768
746
|
|
|
769
747
|
# Auto-enablement checks (when GOOGLE_API_USE_CLIENT_CERTIFICATE is not set)
|
|
770
748
|
|
|
771
|
-
# Check if
|
|
772
|
-
cert_path =
|
|
773
|
-
environment_vars.CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH
|
|
774
|
-
)
|
|
749
|
+
# Check if a workload config file exists.
|
|
750
|
+
cert_path = _get_cert_config_path(include_context_aware=True)
|
|
775
751
|
|
|
776
752
|
if cert_path:
|
|
777
753
|
try:
|
|
778
754
|
with open(cert_path, "r") as f:
|
|
779
755
|
content = json.load(f)
|
|
780
756
|
except (FileNotFoundError, OSError, json.JSONDecodeError) as e:
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
)
|
|
787
|
-
_has_logged_mtls_warning = True
|
|
757
|
+
_LOGGER.debug(
|
|
758
|
+
"mTLS auto-enablement failed: Could not read/parse certificate file at %s. Error: %s",
|
|
759
|
+
cert_path,
|
|
760
|
+
e,
|
|
761
|
+
)
|
|
788
762
|
return False
|
|
789
763
|
|
|
790
764
|
# Structural validation
|
|
@@ -794,12 +768,10 @@ def check_use_client_cert():
|
|
|
794
768
|
return True
|
|
795
769
|
|
|
796
770
|
# If we got here, the file exists but the expected structure is missing
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
)
|
|
802
|
-
_has_logged_mtls_warning = True
|
|
771
|
+
_LOGGER.debug(
|
|
772
|
+
"mTLS auto-enablement failed: Certificate configuration file at %s is missing the required ['cert_configs']['workload'] section.",
|
|
773
|
+
cert_path,
|
|
774
|
+
)
|
|
803
775
|
return False
|
|
804
776
|
|
|
805
777
|
|
|
@@ -24,7 +24,6 @@ from google.auth import environment_vars
|
|
|
24
24
|
from google.auth import exceptions
|
|
25
25
|
from google.auth.transport import _mtls_helper
|
|
26
26
|
|
|
27
|
-
|
|
28
27
|
_LOGGER = logging.getLogger(__name__)
|
|
29
28
|
|
|
30
29
|
|
|
@@ -44,25 +43,18 @@ def has_default_client_cert_source(include_context_aware=True):
|
|
|
44
43
|
Returns:
|
|
45
44
|
bool: indicating if the default client cert source exists.
|
|
46
45
|
"""
|
|
46
|
+
cert_path = _mtls_helper._get_cert_config_path(
|
|
47
|
+
include_context_aware=include_context_aware
|
|
48
|
+
)
|
|
49
|
+
if cert_path is not None:
|
|
50
|
+
return True
|
|
47
51
|
if (
|
|
48
52
|
include_context_aware
|
|
49
53
|
and _mtls_helper._check_config_path(_mtls_helper.CONTEXT_AWARE_METADATA_PATH)
|
|
50
54
|
is not None
|
|
51
55
|
):
|
|
52
56
|
return True
|
|
53
|
-
|
|
54
|
-
_mtls_helper._check_config_path(
|
|
55
|
-
_mtls_helper.CERTIFICATE_CONFIGURATION_DEFAULT_PATH
|
|
56
|
-
)
|
|
57
|
-
is not None
|
|
58
|
-
):
|
|
59
|
-
return True
|
|
60
|
-
cert_config_path = getenv("GOOGLE_API_CERTIFICATE_CONFIG")
|
|
61
|
-
if (
|
|
62
|
-
cert_config_path
|
|
63
|
-
and _mtls_helper._check_config_path(cert_config_path) is not None
|
|
64
|
-
):
|
|
65
|
-
return True
|
|
57
|
+
|
|
66
58
|
return False
|
|
67
59
|
|
|
68
60
|
|
|
@@ -146,7 +138,9 @@ def should_use_client_cert():
|
|
|
146
138
|
If GOOGLE_API_USE_CLIENT_CERTIFICATE is set to true or false, a corresponding
|
|
147
139
|
bool value will be returned
|
|
148
140
|
If GOOGLE_API_USE_CLIENT_CERTIFICATE is unset, the value will be inferred by
|
|
149
|
-
reading a file pointed at by GOOGLE_API_CERTIFICATE_CONFIG
|
|
141
|
+
reading a file pointed at by GOOGLE_API_CERTIFICATE_CONFIG or
|
|
142
|
+
CLOUDSDK_CONTEXT_AWARE_CERTIFICATE_CONFIG_FILE_PATH, or the default path
|
|
143
|
+
like ~/.config/gcloud/certificate_config.json, and verifying it
|
|
150
144
|
contains a "workload" section. If so, the function will return True,
|
|
151
145
|
otherwise False.
|
|
152
146
|
|
|
@@ -208,7 +208,7 @@ class _MutualTlsAdapter(requests.adapters.HTTPAdapter):
|
|
|
208
208
|
google.auth.exceptions.MutualTLSChannelError: If the cert or key is invalid.
|
|
209
209
|
"""
|
|
210
210
|
|
|
211
|
-
def __init__(self, cert, key):
|
|
211
|
+
def __init__(self, cert, key, **kwargs):
|
|
212
212
|
import certifi
|
|
213
213
|
import ssl
|
|
214
214
|
|
|
@@ -250,7 +250,7 @@ class _MutualTlsAdapter(requests.adapters.HTTPAdapter):
|
|
|
250
250
|
self._ctx_poolmanager = ctx_poolmanager
|
|
251
251
|
self._ctx_proxymanager = ctx_proxymanager
|
|
252
252
|
|
|
253
|
-
super(_MutualTlsAdapter, self).__init__()
|
|
253
|
+
super(_MutualTlsAdapter, self).__init__(**kwargs)
|
|
254
254
|
|
|
255
255
|
def init_poolmanager(self, *args, **kwargs):
|
|
256
256
|
kwargs["ssl_context"] = self._ctx_poolmanager
|
|
@@ -457,6 +457,11 @@ class AuthorizedSession(requests.Session):
|
|
|
457
457
|
If the callback is None, application default SSL credentials
|
|
458
458
|
will be used.
|
|
459
459
|
|
|
460
|
+
.. warning::
|
|
461
|
+
Calling this method mutates the underlying `requests.Session` adapter
|
|
462
|
+
dictionary. It is not thread-safe to call this explicitly while other
|
|
463
|
+
threads are making requests.
|
|
464
|
+
|
|
460
465
|
Raises:
|
|
461
466
|
google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
|
|
462
467
|
creation failed for any reason. The existing session state (such
|
|
@@ -475,10 +480,58 @@ class AuthorizedSession(requests.Session):
|
|
|
475
480
|
client_cert_callback
|
|
476
481
|
)
|
|
477
482
|
|
|
483
|
+
old_adapter = self.adapters.get("https://")
|
|
484
|
+
|
|
485
|
+
kwargs = {}
|
|
486
|
+
if old_adapter is not None:
|
|
487
|
+
kwargs["max_retries"] = getattr(old_adapter, "max_retries", 0)
|
|
488
|
+
kwargs["pool_connections"] = getattr(
|
|
489
|
+
old_adapter, "_pool_connections", requests.adapters.DEFAULT_POOLSIZE
|
|
490
|
+
)
|
|
491
|
+
kwargs["pool_maxsize"] = getattr(
|
|
492
|
+
old_adapter, "_pool_maxsize", requests.adapters.DEFAULT_POOLSIZE
|
|
493
|
+
)
|
|
494
|
+
kwargs["pool_block"] = getattr(
|
|
495
|
+
old_adapter, "_pool_block", requests.adapters.DEFAULT_POOLBLOCK
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
old_auth_adapter = None
|
|
499
|
+
auth_kwargs = {}
|
|
500
|
+
if self._auth_request_session is not None:
|
|
501
|
+
old_auth_adapter = self._auth_request_session.adapters.get("https://")
|
|
502
|
+
|
|
503
|
+
if old_auth_adapter is not None:
|
|
504
|
+
auth_kwargs["max_retries"] = getattr(
|
|
505
|
+
old_auth_adapter, "max_retries", 0
|
|
506
|
+
)
|
|
507
|
+
auth_kwargs["pool_connections"] = getattr(
|
|
508
|
+
old_auth_adapter,
|
|
509
|
+
"_pool_connections",
|
|
510
|
+
requests.adapters.DEFAULT_POOLSIZE,
|
|
511
|
+
)
|
|
512
|
+
auth_kwargs["pool_maxsize"] = getattr(
|
|
513
|
+
old_auth_adapter,
|
|
514
|
+
"_pool_maxsize",
|
|
515
|
+
requests.adapters.DEFAULT_POOLSIZE,
|
|
516
|
+
)
|
|
517
|
+
auth_kwargs["pool_block"] = getattr(
|
|
518
|
+
old_auth_adapter,
|
|
519
|
+
"_pool_block",
|
|
520
|
+
requests.adapters.DEFAULT_POOLBLOCK,
|
|
521
|
+
)
|
|
522
|
+
|
|
478
523
|
if is_mtls:
|
|
479
|
-
new_adapter = _MutualTlsAdapter(cert, key)
|
|
524
|
+
new_adapter = _MutualTlsAdapter(cert, key, **kwargs)
|
|
525
|
+
if self._auth_request_session is not None:
|
|
526
|
+
new_auth_adapter = _MutualTlsAdapter(cert, key, **auth_kwargs)
|
|
527
|
+
else:
|
|
528
|
+
new_auth_adapter = None
|
|
480
529
|
else:
|
|
481
|
-
new_adapter = requests.adapters.HTTPAdapter()
|
|
530
|
+
new_adapter = requests.adapters.HTTPAdapter(**kwargs)
|
|
531
|
+
if self._auth_request_session is not None:
|
|
532
|
+
new_auth_adapter = requests.adapters.HTTPAdapter(**auth_kwargs)
|
|
533
|
+
else:
|
|
534
|
+
new_auth_adapter = None
|
|
482
535
|
except (
|
|
483
536
|
exceptions.ClientCertError,
|
|
484
537
|
ImportError,
|
|
@@ -489,6 +542,19 @@ class AuthorizedSession(requests.Session):
|
|
|
489
542
|
raise new_exc from caught_exc
|
|
490
543
|
|
|
491
544
|
self.mount("https://", new_adapter)
|
|
545
|
+
|
|
546
|
+
if old_adapter is not None and old_adapter is not new_adapter:
|
|
547
|
+
old_adapter.close()
|
|
548
|
+
|
|
549
|
+
if self._auth_request_session is not None and new_auth_adapter is not None:
|
|
550
|
+
self._auth_request_session.mount("https://", new_auth_adapter)
|
|
551
|
+
|
|
552
|
+
if (
|
|
553
|
+
old_auth_adapter is not None
|
|
554
|
+
and old_auth_adapter is not new_auth_adapter
|
|
555
|
+
):
|
|
556
|
+
old_auth_adapter.close()
|
|
557
|
+
|
|
492
558
|
self._is_mtls = is_mtls
|
|
493
559
|
if is_mtls:
|
|
494
560
|
self._cached_cert = cert
|
|
@@ -335,6 +335,11 @@ class AuthorizedHttp(RequestMethods): # type: ignore
|
|
|
335
335
|
If the callback is None, application default SSL credentials
|
|
336
336
|
will be used.
|
|
337
337
|
|
|
338
|
+
.. warning::
|
|
339
|
+
Calling this method mutates the underlying `urllib3.PoolManager`.
|
|
340
|
+
It is not thread-safe to call this explicitly while other
|
|
341
|
+
threads are making requests.
|
|
342
|
+
|
|
338
343
|
Returns:
|
|
339
344
|
True if the channel is mutual TLS and False otherwise.
|
|
340
345
|
|
|
@@ -367,9 +372,15 @@ class AuthorizedHttp(RequestMethods): # type: ignore
|
|
|
367
372
|
new_exc = exceptions.MutualTLSChannelError(caught_exc)
|
|
368
373
|
raise new_exc from caught_exc
|
|
369
374
|
|
|
375
|
+
old_http = self.http
|
|
376
|
+
|
|
370
377
|
self.http = new_http
|
|
371
378
|
self._is_mtls = new_is_mtls
|
|
372
379
|
self._request.http = new_http
|
|
380
|
+
|
|
381
|
+
if old_http is not None and old_http is not new_http:
|
|
382
|
+
getattr(old_http, "clear", getattr(old_http, "close", lambda: None))()
|
|
383
|
+
|
|
373
384
|
if new_is_mtls:
|
|
374
385
|
self._cached_cert = cert
|
|
375
386
|
else:
|
|
@@ -491,7 +502,7 @@ class AuthorizedHttp(RequestMethods): # type: ignore
|
|
|
491
502
|
|
|
492
503
|
def __del__(self):
|
|
493
504
|
if hasattr(self, "http") and self.http is not None:
|
|
494
|
-
self.http
|
|
505
|
+
getattr(self.http, "clear", getattr(self.http, "close", lambda: None))()
|
|
495
506
|
|
|
496
507
|
@property
|
|
497
508
|
def headers(self):
|
|
@@ -514,8 +514,12 @@ class Credentials(
|
|
|
514
514
|
|
|
515
515
|
Returns:
|
|
516
516
|
Optional[str]: The URL for the Regional Access Boundary lookup endpoint, or None
|
|
517
|
-
if the service account email is missing.
|
|
517
|
+
if the service account email is missing. Returns None if the subject is populated.
|
|
518
518
|
"""
|
|
519
|
+
if self._subject:
|
|
520
|
+
# RAB does not apply to Workspace User Accounts via Domain-wide Delegation.
|
|
521
|
+
return None
|
|
522
|
+
|
|
519
523
|
if not self.service_account_email:
|
|
520
524
|
_LOGGER.error(
|
|
521
525
|
"Service account email is required to build the Regional Access Boundary lookup URL for service account credentials."
|