Skip to content

Commit 9be6918

Browse files
authored
Merge branch 'main' into py314
2 parents f46a849 + e0c3296 commit 9be6918

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2234
-301
lines changed

.github/.OwlBot.lock.yaml

Lines changed: 0 additions & 17 deletions
This file was deleted.

.github/.OwlBot.yaml

Lines changed: 0 additions & 18 deletions
This file was deleted.

.github/release-please.yml

Lines changed: 0 additions & 2 deletions
This file was deleted.

.github/release-trigger.yml

Lines changed: 0 additions & 1 deletion
This file was deleted.

.librarian/config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
global_files_allowlist:
2+
# Allow the container to read and write the root `CHANGELOG.md`
3+
# file during the `release` step to update the latest client library
4+
# versions which are hardcoded in the file.
5+
- path: "CHANGELOG.md"
6+
permissions: "read-write"

.librarian/state.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator:latest
2+
libraries:
3+
- id: google-auth
4+
version: 2.43.0
5+
last_generated_commit: 102d9f92ac6ed649a61efd9b208e4d1de278e9bb
6+
apis: []
7+
source_roots:
8+
- .
9+
preserve_regex: []
10+
remove_regex: []
11+
tag_format: v{version}

CHANGELOG.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,61 @@
44

55
[1]: https://pypi.org/project/google-auth/#history
66

7+
## [2.43.0](https://github.com/googleapis/google-cloud-python/compare/google-auth-v2.42.1...google-auth-v2.43.0) (2025-11-05)
8+
9+
10+
### Features
11+
12+
* Add public wrapper for _mtls_helper.check_use_client_cert which enables mTLS if GOOGLE_API_USE_CLIENT_CERTIFICATE is not set, when the MWID/X.509 cert sources detected (#1859) Add public wrapper for check_use_client_cert which enables mTLS if
13+
GOOGLE_API_USE_CLIENT_CERTIFICATE is not set, when the MWID/X.509 cert
14+
sources detected. Also, fix check_use_client_cert to return boolean
15+
value.
16+
Change #1848 added the check_use_client_cert method that helps know if
17+
client cert should be used for mTLS connection. However, that was in a
18+
private class, thus, created a public wrapper of the same function so
19+
that it can be used by python Client Libraries. Also, updated
20+
check_use_client_cert to return a boolean value instead of existing
21+
string value for better readability and future scope.
22+
--------- ([1535eccbff0ad8f3fd6a9775316ac8b77dca66ba](https://github.com/googleapis/google-cloud-python/commit/1535eccbff0ad8f3fd6a9775316ac8b77dca66ba))
23+
* Enable mTLS if GOOGLE_API_USE_CLIENT_CERTIFICATE is not set, if the MWID/X.509 cert sources detected (#1848) The Python SDK will use a hybrid approach for mTLS enablement:
24+
- If the GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable is set
25+
(either true or false), the SDK will respect that setting. This is
26+
necessary for test scenarios and users who need to explicitly control
27+
mTLS behavior.
28+
- If the GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable is not
29+
set, the SDK will automatically enable mTLS only if it detects Managed
30+
Workload Identity (MWID) or X.509 Workforce Identity Federation (WIF)
31+
certificate sources. In other cases where the variable is not set, mTLS
32+
will remain disabled.
33+
** This change also adds the helper method `check_use_client_cert` and
34+
it's unit test, which will be used for checking the criteria for setting
35+
the mTLS to true
36+
** This change is only for Auth-Library, other changes will be created
37+
for Client-Library use-cases.
38+
--------- ([395e405b64b56ddb82ee639958c2e8056ad2e82b](https://github.com/googleapis/google-cloud-python/commit/395e405b64b56ddb82ee639958c2e8056ad2e82b))
39+
* onboard `google-auth` to librarian (#1838) This PR onboards `google-auth` library to the Librarian system.
40+
Wait for
41+
https://github.com/googleapis/google-auth-library-python/pull/1819. ([c503eaa511357d7a76cc1e1f1d3a3be2dabd5bca](https://github.com/googleapis/google-cloud-python/commit/c503eaa511357d7a76cc1e1f1d3a3be2dabd5bca))
42+
43+
## [2.42.1](https://github.com/googleapis/google-auth-library-python/compare/v2.42.0...v2.42.1) (2025-10-30)
44+
45+
46+
### Bug Fixes
47+
48+
* Catch ValueError for json.loads() ([#1842](https://github.com/googleapis/google-auth-library-python/issues/1842)) ([b074cad](https://github.com/googleapis/google-auth-library-python/commit/b074cad460589633adfc6744c01726ae86f2aa2b))
49+
50+
## [2.42.0](https://github.com/googleapis/google-auth-library-python/compare/v2.41.1...v2.42.0) (2025-10-24)
51+
52+
53+
### Features
54+
55+
* Add trust boundary support for external accounts. ([#1809](https://github.com/googleapis/google-auth-library-python/issues/1809)) ([36ecb1d](https://github.com/googleapis/google-auth-library-python/commit/36ecb1d65883477d27faf9c2281fc289659b9903))
56+
57+
58+
### Bug Fixes
59+
60+
* Read scopes from ADC json for impersoanted cred ([#1820](https://github.com/googleapis/google-auth-library-python/issues/1820)) ([62c0fc8](https://github.com/googleapis/google-auth-library-python/commit/62c0fc82a3625542381f85c698595446fc99ddae))
61+
762
## [2.41.1](https://github.com/googleapis/google-auth-library-python/compare/v2.41.0...v2.41.1) (2025-09-30)
863

964

google/auth/_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ def _parse_request_body(body: Optional[bytes], content_type: str = "") -> Any:
489489
if not content_type or "application/json" in content_type:
490490
try:
491491
return json.loads(body_str)
492-
except (json.JSONDecodeError, TypeError):
492+
except (TypeError, ValueError):
493493
return body_str
494494
if "application/x-www-form-urlencoded" in content_type:
495495
parsed_query = urllib.parse.parse_qs(body_str)

google/auth/_service_account_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def from_dict(data, require=None, use_rsa_signer=True):
5656
if use_rsa_signer:
5757
signer = crypt.RSASigner.from_service_account_info(data)
5858
else:
59-
signer = crypt.ES256Signer.from_service_account_info(data)
59+
signer = crypt.EsSigner.from_service_account_info(data)
6060

6161
return signer
6262

google/auth/compute_engine/_metadata.py

Lines changed: 101 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,72 @@
2424
import os
2525
from urllib.parse import urljoin
2626

27+
import requests
28+
2729
from google.auth import _helpers
2830
from google.auth import environment_vars
2931
from google.auth import exceptions
3032
from google.auth import metrics
3133
from google.auth import transport
3234
from google.auth._exponential_backoff import ExponentialBackoff
35+
from google.auth.compute_engine import _mtls
36+
3337

3438
_LOGGER = logging.getLogger(__name__)
3539

40+
_GCE_DEFAULT_MDS_IP = "169.254.169.254"
41+
_GCE_DEFAULT_HOST = "metadata.google.internal"
42+
_GCE_DEFAULT_MDS_HOSTS = [_GCE_DEFAULT_HOST, _GCE_DEFAULT_MDS_IP]
43+
3644
# Environment variable GCE_METADATA_HOST is originally named
3745
# GCE_METADATA_ROOT. For compatibility reasons, here it checks
3846
# the new variable first; if not set, the system falls back
3947
# to the old variable.
4048
_GCE_METADATA_HOST = os.getenv(environment_vars.GCE_METADATA_HOST, None)
4149
if not _GCE_METADATA_HOST:
4250
_GCE_METADATA_HOST = os.getenv(
43-
environment_vars.GCE_METADATA_ROOT, "metadata.google.internal"
51+
environment_vars.GCE_METADATA_ROOT, _GCE_DEFAULT_HOST
52+
)
53+
54+
55+
def _validate_gce_mds_configured_environment():
56+
"""Validates the GCE metadata server environment configuration for mTLS.
57+
58+
mTLS is only supported when connecting to the default metadata server hosts.
59+
If we are in strict mode (which requires mTLS), ensure that the metadata host
60+
has not been overridden to a custom value (which means mTLS will fail).
61+
62+
Raises:
63+
google.auth.exceptions.MutualTLSChannelError: if the environment
64+
configuration is invalid for mTLS.
65+
"""
66+
mode = _mtls._parse_mds_mode()
67+
if mode == _mtls.MdsMtlsMode.STRICT:
68+
# mTLS is only supported when connecting to the default metadata host.
69+
# Raise an exception if we are in strict mode (which requires mTLS)
70+
# but the metadata host has been overridden to a custom MDS. (which means mTLS will fail)
71+
if _GCE_METADATA_HOST not in _GCE_DEFAULT_MDS_HOSTS:
72+
raise exceptions.MutualTLSChannelError(
73+
"Mutual TLS is required, but the metadata host has been overridden. "
74+
"mTLS is only supported when connecting to the default metadata host."
75+
)
76+
77+
78+
def _get_metadata_root(use_mtls: bool):
79+
"""Returns the metadata server root URL."""
80+
81+
scheme = "https" if use_mtls else "http"
82+
return "{}://{}/computeMetadata/v1/".format(scheme, _GCE_METADATA_HOST)
83+
84+
85+
def _get_metadata_ip_root(use_mtls: bool):
86+
"""Returns the metadata server IP root URL."""
87+
scheme = "https" if use_mtls else "http"
88+
return "{}://{}".format(
89+
scheme, os.getenv(environment_vars.GCE_METADATA_IP, _GCE_DEFAULT_MDS_IP)
4490
)
45-
_METADATA_ROOT = "http://{}/computeMetadata/v1/".format(_GCE_METADATA_HOST)
4691

47-
# This is used to ping the metadata server, it avoids the cost of a DNS
48-
# lookup.
49-
_METADATA_IP_ROOT = "http://{}".format(
50-
os.getenv(environment_vars.GCE_METADATA_IP, "169.254.169.254")
51-
)
92+
5293
_METADATA_FLAVOR_HEADER = "metadata-flavor"
5394
_METADATA_FLAVOR_VALUE = "Google"
5495
_METADATA_HEADERS = {_METADATA_FLAVOR_HEADER: _METADATA_FLAVOR_VALUE}
@@ -102,6 +143,33 @@ def detect_gce_residency_linux():
102143
return content.startswith(_GOOGLE)
103144

104145

146+
def _prepare_request_for_mds(request, use_mtls=False) -> None:
147+
"""Prepares a request for the metadata server.
148+
149+
This will check if mTLS should be used and mount the mTLS adapter if needed.
150+
151+
Args:
152+
request (google.auth.transport.Request): A callable used to make
153+
HTTP requests.
154+
use_mtls (bool): Whether to use mTLS for the request.
155+
156+
Returns:
157+
google.auth.transport.Request: A request object to use.
158+
If mTLS is enabled, the request will have the mTLS adapter mounted.
159+
Otherwise, the original request will be returned unchanged.
160+
"""
161+
# Only modify the request if mTLS is enabled.
162+
if use_mtls:
163+
# Ensure the request has a session to mount the adapter to.
164+
if not request.session:
165+
request.session = requests.Session()
166+
167+
adapter = _mtls.MdsMtlsAdapter()
168+
# Mount the adapter for all default GCE metadata hosts.
169+
for host in _GCE_DEFAULT_MDS_HOSTS:
170+
request.session.mount(f"https://{host}/", adapter)
171+
172+
105173
def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
106174
"""Checks to see if the metadata server is available.
107175
@@ -115,6 +183,8 @@ def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
115183
Returns:
116184
bool: True if the metadata server is reachable, False otherwise.
117185
"""
186+
use_mtls = _mtls.should_use_mds_mtls()
187+
_prepare_request_for_mds(request, use_mtls=use_mtls)
118188
# NOTE: The explicit ``timeout`` is a workaround. The underlying
119189
# issue is that resolving an unknown host on some networks will take
120190
# 20-30 seconds; making this timeout short fixes the issue, but
@@ -129,7 +199,10 @@ def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
129199
for attempt in backoff:
130200
try:
131201
response = request(
132-
url=_METADATA_IP_ROOT, method="GET", headers=headers, timeout=timeout
202+
url=_get_metadata_ip_root(use_mtls),
203+
method="GET",
204+
headers=headers,
205+
timeout=timeout,
133206
)
134207

135208
metadata_flavor = response.headers.get(_METADATA_FLAVOR_HEADER)
@@ -153,7 +226,7 @@ def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
153226
def get(
154227
request,
155228
path,
156-
root=_METADATA_ROOT,
229+
root=None,
157230
params=None,
158231
recursive=False,
159232
retry_count=5,
@@ -168,7 +241,8 @@ def get(
168241
HTTP requests.
169242
path (str): The resource to retrieve. For example,
170243
``'instance/service-accounts/default'``.
171-
root (str): The full path to the metadata server root.
244+
root (Optional[str]): The full path to the metadata server root. If not
245+
provided, the default root will be used.
172246
params (Optional[Mapping[str, str]]): A mapping of query parameter
173247
keys to values.
174248
recursive (bool): Whether to do a recursive query of metadata. See
@@ -189,7 +263,24 @@ def get(
189263
Raises:
190264
google.auth.exceptions.TransportError: if an error occurred while
191265
retrieving metadata.
266+
google.auth.exceptions.MutualTLSChannelError: if using mtls and the environment
267+
configuration is invalid for mTLS (for example, the metadata host
268+
has been overridden in strict mTLS mode).
269+
192270
"""
271+
use_mtls = _mtls.should_use_mds_mtls()
272+
# Prepare the request object for mTLS if needed.
273+
# This will create a new request object with the mTLS session.
274+
_prepare_request_for_mds(request, use_mtls=use_mtls)
275+
276+
if root is None:
277+
root = _get_metadata_root(use_mtls)
278+
279+
# mTLS is only supported when connecting to the default metadata host.
280+
# If we are in strict mode (which requires mTLS), ensure that the metadata host
281+
# has not been overridden to a non-default host value (which means mTLS will fail).
282+
_validate_gce_mds_configured_environment()
283+
193284
base_url = urljoin(root, path)
194285
query_params = {} if params is None else params
195286

0 commit comments

Comments
 (0)