Skip to content

Commit 91beb2d

Browse files
committed
Merge branch 'main' into remove-rsa-dependency
2 parents fb84373 + 78de790 commit 91beb2d

File tree

4 files changed

+158
-13
lines changed

4 files changed

+158
-13
lines changed

google/auth/transport/_mtls_helper.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@
4747
b"-----BEGIN PASSPHRASE-----(.+)-----END PASSPHRASE-----", re.DOTALL
4848
)
4949

50+
# Temporary patch to accomodate incorrect cert config in Cloud Run prod environment.
51+
_WELL_KNOWN_CLOUD_RUN_CERT_PATH = (
52+
"/var/run/secrets/workload-spiffe-credentials/certificates.pem"
53+
)
54+
_WELL_KNOWN_CLOUD_RUN_KEY_PATH = (
55+
"/var/run/secrets/workload-spiffe-credentials/private_key.pem"
56+
)
57+
_INCORRECT_CLOUD_RUN_CERT_PATH = (
58+
"/var/lib/volumes/certificate/workload-certificates/certificates.pem"
59+
)
60+
_INCORRECT_CLOUD_RUN_KEY_PATH = (
61+
"/var/lib/volumes/certificate/workload-certificates/private_key.pem"
62+
)
63+
5064

5165
def _check_config_path(config_path):
5266
"""Checks for config file path. If it exists, returns the absolute path with user expansion;
@@ -183,6 +197,25 @@ def _get_workload_cert_and_key_paths(config_path):
183197
)
184198
key_path = workload["key_path"]
185199

200+
# == BEGIN Temporary Cloud Run PATCH ==
201+
# See https://github.com/googleapis/google-auth-library-python/issues/1881
202+
if (cert_path == _INCORRECT_CLOUD_RUN_CERT_PATH) and (
203+
key_path == _INCORRECT_CLOUD_RUN_KEY_PATH
204+
):
205+
if not path.exists(cert_path) and not path.exists(key_path):
206+
_LOGGER.debug(
207+
"Applying Cloud Run certificate path patch. "
208+
"Configured paths not found: %s, %s. "
209+
"Using well-known paths: %s, %s",
210+
cert_path,
211+
key_path,
212+
_WELL_KNOWN_CLOUD_RUN_CERT_PATH,
213+
_WELL_KNOWN_CLOUD_RUN_KEY_PATH,
214+
)
215+
cert_path = _WELL_KNOWN_CLOUD_RUN_CERT_PATH
216+
key_path = _WELL_KNOWN_CLOUD_RUN_KEY_PATH
217+
# == END Temporary Cloud Run PATCH ==
218+
186219
return cert_path, key_path
187220

188221

@@ -279,7 +312,7 @@ def _run_cert_provider_command(command, expect_encrypted_key=False):
279312
def get_client_ssl_credentials(
280313
generate_encrypted_key=False,
281314
context_aware_metadata_path=CONTEXT_AWARE_METADATA_PATH,
282-
certificate_config_path=CERTIFICATE_CONFIGURATION_DEFAULT_PATH,
315+
certificate_config_path=None,
283316
):
284317
"""Returns the client side certificate, private key and passphrase.
285318
@@ -306,13 +339,10 @@ def get_client_ssl_credentials(
306339
the cert, key and passphrase.
307340
"""
308341

309-
# 1. Check for certificate config json.
310-
cert_config_path = _check_config_path(certificate_config_path)
311-
if cert_config_path:
312-
# Attempt to retrieve X.509 Workload cert and key.
313-
cert, key = _get_workload_cert_and_key(cert_config_path)
314-
if cert and key:
315-
return True, cert, key, None
342+
# 1. Attempt to retrieve X.509 Workload cert and key.
343+
cert, key = _get_workload_cert_and_key(certificate_config_path)
344+
if cert and key:
345+
return True, cert, key, None
316346

317347
# 2. Check for context aware metadata json
318348
metadata_path = _check_config_path(context_aware_metadata_path)

system_tests/system_tests_async/test_default.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616
import pytest
1717

1818
from google.auth import _default_async
19+
from google.auth.exceptions import RefreshError
20+
21+
EXPECT_PROJECT_ID = os.getenv("EXPECT_PROJECT_ID")
22+
CREDENTIALS = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", "")
1923

20-
EXPECT_PROJECT_ID = os.environ.get("EXPECT_PROJECT_ID")
2124

2225
@pytest.mark.asyncio
2326
async def test_application_default_credentials(verify_refresh):
@@ -26,4 +29,10 @@ async def test_application_default_credentials(verify_refresh):
2629
if EXPECT_PROJECT_ID is not None:
2730
assert project_id is not None
2831

29-
await verify_refresh(credentials)
32+
try:
33+
await verify_refresh(credentials)
34+
except RefreshError as e:
35+
# allow expired credentials for explicit_authorized_user tests
36+
# TODO: https://github.com/googleapis/google-auth-library-python/issues/1882
37+
if not CREDENTIALS.endswith("authorized_user.json") or "Token has been expired or revoked" not in str(e):
38+
raise

system_tests/system_tests_sync/test_default.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
import os
1616

1717
import google.auth
18+
from google.auth.exceptions import RefreshError
1819

19-
EXPECT_PROJECT_ID = os.environ.get("EXPECT_PROJECT_ID")
20+
EXPECT_PROJECT_ID = os.getenv("EXPECT_PROJECT_ID")
21+
CREDENTIALS = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", "")
2022

2123

2224
def test_application_default_credentials(verify_refresh):
@@ -25,4 +27,10 @@ def test_application_default_credentials(verify_refresh):
2527
if EXPECT_PROJECT_ID is not None:
2628
assert project_id is not None
2729

28-
verify_refresh(credentials)
30+
try:
31+
verify_refresh(credentials)
32+
except RefreshError as e:
33+
# allow expired credentials for explicit_authorized_user tests
34+
# TODO: https://github.com/googleapis/google-auth-library-python/issues/1882
35+
if not CREDENTIALS.endswith("authorized_user.json") or "Token has been expired or revoked" not in str(e):
36+
raise

tests/transport/test__mtls_helper.py

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,102 @@ def test_success_with_certificate_config(
334334
assert key == pytest.private_key_bytes
335335
assert passphrase is None
336336

337+
@mock.patch(
338+
"google.auth.transport._mtls_helper._read_cert_and_key_files", autospec=True
339+
)
340+
@mock.patch(
341+
"google.auth.transport._mtls_helper._get_cert_config_path", autospec=True
342+
)
343+
@mock.patch("google.auth.transport._mtls_helper._load_json_file", autospec=True)
337344
@mock.patch("google.auth.transport._mtls_helper._check_config_path", autospec=True)
338-
def test_success_without_metadata(self, mock_check_config_path):
345+
def test_success_with_certificate_config_cloud_run_patch(
346+
self,
347+
mock_check_config_path,
348+
mock_load_json_file,
349+
mock_get_cert_config_path,
350+
mock_read_cert_and_key_files,
351+
):
352+
cert_config_path = "/path/to/config"
353+
mock_check_config_path.return_value = cert_config_path
354+
mock_load_json_file.return_value = {
355+
"cert_configs": {
356+
"workload": {
357+
"cert_path": _mtls_helper._INCORRECT_CLOUD_RUN_CERT_PATH,
358+
"key_path": _mtls_helper._INCORRECT_CLOUD_RUN_KEY_PATH,
359+
}
360+
}
361+
}
362+
mock_get_cert_config_path.return_value = cert_config_path
363+
mock_read_cert_and_key_files.return_value = (
364+
pytest.public_cert_bytes,
365+
pytest.private_key_bytes,
366+
)
367+
368+
has_cert, cert, key, passphrase = _mtls_helper.get_client_ssl_credentials()
369+
assert has_cert
370+
assert cert == pytest.public_cert_bytes
371+
assert key == pytest.private_key_bytes
372+
assert passphrase is None
373+
374+
mock_read_cert_and_key_files.assert_called_once_with(
375+
_mtls_helper._WELL_KNOWN_CLOUD_RUN_CERT_PATH,
376+
_mtls_helper._WELL_KNOWN_CLOUD_RUN_KEY_PATH,
377+
)
378+
379+
@mock.patch("os.path.exists", autospec=True)
380+
@mock.patch(
381+
"google.auth.transport._mtls_helper._read_cert_and_key_files", autospec=True
382+
)
383+
@mock.patch(
384+
"google.auth.transport._mtls_helper._get_cert_config_path", autospec=True
385+
)
386+
@mock.patch("google.auth.transport._mtls_helper._load_json_file", autospec=True)
387+
@mock.patch("google.auth.transport._mtls_helper._check_config_path", autospec=True)
388+
def test_success_with_certificate_config_cloud_run_patch_skipped_if_cert_exists(
389+
self,
390+
mock_check_config_path,
391+
mock_load_json_file,
392+
mock_get_cert_config_path,
393+
mock_read_cert_and_key_files,
394+
mock_os_path_exists,
395+
):
396+
cert_config_path = "/path/to/config"
397+
mock_check_config_path.return_value = cert_config_path
398+
mock_os_path_exists.return_value = True
399+
mock_load_json_file.return_value = {
400+
"cert_configs": {
401+
"workload": {
402+
"cert_path": _mtls_helper._INCORRECT_CLOUD_RUN_CERT_PATH,
403+
"key_path": _mtls_helper._INCORRECT_CLOUD_RUN_KEY_PATH,
404+
}
405+
}
406+
}
407+
mock_get_cert_config_path.return_value = cert_config_path
408+
mock_read_cert_and_key_files.return_value = (
409+
pytest.public_cert_bytes,
410+
pytest.private_key_bytes,
411+
)
412+
413+
has_cert, cert, key, passphrase = _mtls_helper.get_client_ssl_credentials()
414+
assert has_cert
415+
assert cert == pytest.public_cert_bytes
416+
assert key == pytest.private_key_bytes
417+
assert passphrase is None
418+
419+
mock_read_cert_and_key_files.assert_called_once_with(
420+
_mtls_helper._INCORRECT_CLOUD_RUN_CERT_PATH,
421+
_mtls_helper._INCORRECT_CLOUD_RUN_KEY_PATH,
422+
)
423+
424+
@mock.patch(
425+
"google.auth.transport._mtls_helper._get_workload_cert_and_key", autospec=True
426+
)
427+
@mock.patch("google.auth.transport._mtls_helper._check_config_path", autospec=True)
428+
def test_success_without_metadata(
429+
self, mock_check_config_path, mock_get_workload_cert_and_key
430+
):
339431
mock_check_config_path.return_value = False
432+
mock_get_workload_cert_and_key.return_value = (None, None)
340433
has_cert, cert, key, passphrase = _mtls_helper.get_client_ssl_credentials()
341434
assert not has_cert
342435
assert cert is None
@@ -395,12 +488,17 @@ def test_missing_cert_command(
395488
)
396489
@mock.patch("google.auth.transport._mtls_helper._load_json_file", autospec=True)
397490
@mock.patch("google.auth.transport._mtls_helper._check_config_path", autospec=True)
491+
@mock.patch(
492+
"google.auth.transport._mtls_helper._get_workload_cert_and_key", autospec=True
493+
)
398494
def test_customize_context_aware_metadata_path(
399495
self,
496+
mock_get_workload_cert_and_key,
400497
mock_check_config_path,
401498
mock_load_json_file,
402499
mock_run_cert_provider_command,
403500
):
501+
mock_get_workload_cert_and_key.return_value = (None, None)
404502
context_aware_metadata_path = "/path/to/metata/data"
405503
mock_check_config_path.return_value = context_aware_metadata_path
406504
mock_load_json_file.return_value = {"cert_provider_command": ["command"]}

0 commit comments

Comments
 (0)