Skip to content

Commit 08bcf25

Browse files
committed
fix(auth): resolve mTLS transport state and gRPC workload certificate issues.
1 parent 6b62cb6 commit 08bcf25

6 files changed

Lines changed: 76 additions & 5 deletions

File tree

packages/google-auth/google/auth/aio/transport/sessions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ async def _do_configure():
207207
self._auth_request = AiohttpRequest(session=new_session)
208208

209209
await old_auth_request.close()
210+
else:
211+
self._is_mtls = False
210212

211213
except (
212214
exceptions.ClientCertError,

packages/google-auth/google/auth/transport/grpc.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from google.auth import exceptions
2222
from google.auth.transport import _mtls_helper
23+
from google.auth.transport import mtls
2324
from google.oauth2 import service_account
2425

2526
try:
@@ -295,11 +296,7 @@ def __init__(self):
295296
if not use_client_cert:
296297
self._is_mtls = False
297298
else:
298-
# Load client SSL credentials.
299-
metadata_path = _mtls_helper._check_config_path(
300-
_mtls_helper.CONTEXT_AWARE_METADATA_PATH
301-
)
302-
self._is_mtls = metadata_path is not None
299+
self._is_mtls = mtls.has_default_client_cert_source()
303300

304301
@property
305302
def ssl_credentials(self):

packages/google-auth/google/auth/transport/urllib3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ def configure_mtls_channel(self, client_cert_callback=None):
357357
self._cached_cert = cert
358358
else:
359359
self.http = _make_default_http()
360+
self._is_mtls = False
360361
except (
361362
exceptions.ClientCertError,
362363
ImportError,

packages/google-auth/tests/transport/aio/test_sessions_mtls.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from google.auth import exceptions
2323
from google.auth.aio import credentials
24+
from google.auth.aio import transport
2425
from google.auth.aio.transport import sessions
2526

2627
# This is the valid "workload" format the library expects
@@ -140,3 +141,37 @@ def mock_callback():
140141
await session.configure_mtls_channel(client_cert_callback=mock_callback)
141142

142143
assert session._is_mtls is True
144+
145+
@pytest.mark.asyncio
146+
async def test_configure_mtls_channel_custom_request(self):
147+
"""
148+
Tests that if _auth_request is not an AiohttpRequest, _is_mtls is set to False
149+
because we can't configure the custom request with mTLS.
150+
"""
151+
with mock.patch.dict(
152+
os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}
153+
), mock.patch("os.path.exists") as mock_exists, mock.patch(
154+
"builtins.open", mock.mock_open(read_data=json.dumps(VALID_WORKLOAD_CONFIG))
155+
), mock.patch(
156+
"google.auth.aio.transport.mtls.get_client_cert_and_key"
157+
) as mock_helper, mock.patch(
158+
"google.auth.aio.transport.mtls.make_client_cert_ssl_context"
159+
) as mock_make_context:
160+
mock_exists.return_value = True
161+
mock_helper.return_value = (True, b"fake_cert_data", b"fake_key_data")
162+
163+
mock_context = mock.Mock(spec=ssl.SSLContext)
164+
mock_make_context.return_value = mock_context
165+
166+
mock_creds = mock.AsyncMock(spec=credentials.Credentials)
167+
mock_auth_request = mock.AsyncMock(spec=transport.Request)
168+
session = sessions.AsyncAuthorizedSession(mock_creds, auth_request=mock_auth_request)
169+
170+
await session.configure_mtls_channel()
171+
172+
# If the request handler is not an AiohttpRequest, the library cannot configure
173+
# the connection to use mTLS, so _is_mtls must be False to reflect this unconfigured state.
174+
assert session._is_mtls is False
175+
mock_make_context.assert_called_once_with(
176+
b"fake_cert_data", b"fake_key_data"
177+
)

packages/google-auth/tests/transport/test_grpc.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,39 @@ def test_get_client_ssl_credentials_success(
468468
certificate_chain=PUBLIC_CERT_BYTES, private_key=PRIVATE_KEY_BYTES
469469
)
470470

471+
@mock.patch("google.auth.transport.mtls.has_default_client_cert_source", autospec=True)
472+
def test_get_client_ssl_credentials_workload_cert(
473+
self,
474+
mock_has_default_client_cert_source,
475+
mock_check_config_path,
476+
mock_load_json_file,
477+
mock_get_client_ssl_credentials,
478+
mock_ssl_channel_credentials,
479+
):
480+
# Mock that context-aware metadata does not exist, but workload cert config does.
481+
mock_check_config_path.return_value = None
482+
mock_has_default_client_cert_source.return_value = True
483+
mock_get_client_ssl_credentials.return_value = (
484+
True,
485+
PUBLIC_CERT_BYTES,
486+
PRIVATE_KEY_BYTES,
487+
None,
488+
)
489+
490+
with mock.patch.dict(
491+
os.environ, {environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE: "true"}
492+
):
493+
ssl_credentials = google.auth.transport.grpc.SslCredentials()
494+
495+
# If a workload certificate config exists on the device (and use_client_cert is true),
496+
# is_mtls must be True and get_client_ssl_credentials should be invoked.
497+
assert ssl_credentials.ssl_credentials is not None
498+
assert ssl_credentials.is_mtls
499+
mock_get_client_ssl_credentials.assert_called_once()
500+
mock_ssl_channel_credentials.assert_called_once_with(
501+
certificate_chain=PUBLIC_CERT_BYTES, private_key=PRIVATE_KEY_BYTES
502+
)
503+
471504
def test_get_client_ssl_credentials_without_client_cert_env(
472505
self,
473506
mock_check_config_path,

packages/google-auth/tests/transport/test_urllib3.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ def test_configure_mtls_channel_non_mtls(
262262
is_mtls = authed_http.configure_mtls_channel()
263263

264264
assert not is_mtls
265+
# If client certificate and key are not found, the transport falls back to
266+
# a standard connection. _is_mtls must be False to reflect this fallback state.
267+
assert authed_http._is_mtls is False
265268
mock_get_client_cert_and_key.assert_called_once()
266269
mock_make_mutual_tls_http.assert_not_called()
267270

0 commit comments

Comments
 (0)