Skip to content

Commit 09b6a1e

Browse files
fix: Use monkeypatch in test to update env variable, update helper method to catch exceptions and update docstring
Signed-off-by: Radhika Agrawal <agrawalradhika@google.com>
1 parent a06bcb1 commit 09b6a1e

File tree

2 files changed

+100
-33
lines changed

2 files changed

+100
-33
lines changed

google/auth/transport/_mtls_helper.py

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
import json
1818
import logging
19-
from os import environ, path
20-
import os
19+
from os import environ, path, getenv
2120
import re
2221
import subprocess
2322

@@ -407,29 +406,52 @@ def client_cert_callback():
407406
# Then dump the decrypted key bytes
408407
return crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
409408

409+
410410
def check_use_client_cert():
411-
"""Returns whether the client certificate should to be used for mTLS.
412-
413-
Returns:
414-
str:
415-
A boolean indicating if client certificate should be used.
416-
The value is "true" or "false" or unset.
417-
If unset, the function checks if the GOOGLE_API_CERTIFICATE_CONFIG
418-
environment variable is set. If it is set, the function returns
419-
"true" if the certificate config file contains "workload" section
420-
and "false" otherwise.
421-
"""
422-
use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE")
423-
### Check if the value of GOOGLE_API_USE_CLIENT_CERTIFICATE is unset.
424-
if not use_client_cert:
425-
cert_path = os.getenv("GOOGLE_API_CERTIFICATE_CONFIG")
426-
if cert_path:
427-
with open(cert_path, "r") as f:
428-
content = json.load(f)
429-
if "cert_configs" in content and "workload" in content['cert_configs']:
430-
return "true"
431-
return "false"
432-
else:
433-
### Return the value of GOOGLE_API_USE_CLIENT_CERTIFICATE which is set.
434-
return use_client_cert
411+
"""Returns whether the client certificate should to be used for mTLS.
412+
413+
The function checks the value of GOOGLE_API_USE_CLIENT_CERTIFICATE
414+
environment variable, and GOOGLE_API_CERTIFICATE_CONFIG environment variable
415+
if the former is not set. If GOOGLE_API_USE_CLIENT_CERTIFICATE is set,
416+
this helper function returns the value of the former. If it is unset, this
417+
helper function checks if GOOGLE_API_CERTIFICATE_CONFIG is set. If it is set,
418+
this helper function returns "true" if the certificate config file contains
419+
"workload" section and "false" otherwise.
435420
421+
Returns:
422+
str: A string("true" or "false") indicating if client certificate should
423+
be used.
424+
"""
425+
use_client_cert = getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE")
426+
# Check if the value of GOOGLE_API_USE_CLIENT_CERTIFICATE is set.
427+
if use_client_cert:
428+
return use_client_cert.lower()
429+
else:
430+
# Check if the value of GOOGLE_API_CERTIFICATE_CONFIG is set.
431+
cert_path = getenv("GOOGLE_API_CERTIFICATE_CONFIG")
432+
if cert_path:
433+
try:
434+
with open(cert_path, "r") as f:
435+
content = json.load(f)
436+
except json.JSONDecodeError:
437+
_LOGGER.debug("JSON decode error.")
438+
return "false"
439+
except FileNotFoundError:
440+
_LOGGER.debug("Certificate config file not found.")
441+
return "false"
442+
except OSError:
443+
_LOGGER.debug("OS error.")
444+
return "false"
445+
try:
446+
if content["cert_configs"]["workload"]:
447+
return "true"
448+
except KeyError:
449+
_LOGGER.debug(
450+
"Certificate config file content does not contain 'workload'"
451+
" section in 'cert_configs'."
452+
)
453+
return "false"
454+
except TypeError:
455+
_LOGGER.debug("Certificate config file content is not a JSON object.")
456+
return "false"
457+
return "false"

tests/transport/test__mtls_helper.py

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -640,12 +640,12 @@ def test_crypto_error(self):
640640
ENCRYPTED_EC_PRIVATE_KEY, b"wrong_password"
641641
)
642642

643-
def test_check_use_client_cert(self):
644-
os.environ["GOOGLE_API_USE_CLIENT_CERTIFICATE"] = "true"
643+
def test_check_use_client_cert(self, monkeypatch):
644+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "true")
645645
use_client_cert = _mtls_helper.check_use_client_cert()
646646
assert use_client_cert == "true"
647647

648-
def test_check_use_client_cert_for_workload_with_config_file(self):
648+
def test_check_use_client_cert_for_workload_with_config_file(self, monkeypatch):
649649
config_data = {
650650
"version": 1,
651651
"cert_configs": {
@@ -657,11 +657,56 @@ def test_check_use_client_cert_for_workload_with_config_file(self):
657657
}
658658
config_filename = "mock_certificate_config.json"
659659
config_file_content = json.dumps(config_data)
660+
monkeypatch.setenv("GOOGLE_API_CERTIFICATE_CONFIG", config_filename)
661+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
660662
# Use mock_open to simulate the file in memory
661-
m = mock.mock_open(read_data=config_file_content)
662-
with mock.patch("builtins.open", m):
663-
os.environ["GOOGLE_API_CERTIFICATE_CONFIG"] = config_filename
664-
os.environ["GOOGLE_API_USE_CLIENT_CERTIFICATE"] = ""
663+
mock_file_handle = mock.mock_open(read_data=config_file_content)
664+
with mock.patch("builtins.open", mock_file_handle):
665665
use_client_cert = _mtls_helper.check_use_client_cert()
666666
assert use_client_cert == "true"
667667

668+
def test_check_use_client_cert_false(self, monkeypatch):
669+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
670+
use_client_cert = _mtls_helper.check_use_client_cert()
671+
assert use_client_cert == "false"
672+
673+
def test_check_use_client_cert_for_workload_with_config_file_not_found(
674+
self, monkeypatch
675+
):
676+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
677+
use_client_cert = _mtls_helper.check_use_client_cert()
678+
assert use_client_cert == "false"
679+
680+
def test_check_use_client_cert_for_workload_with_config_file_not_json(
681+
self, monkeypatch
682+
):
683+
config_filename = "mock_certificate_config.json"
684+
config_file_content = "not_valid_json"
685+
monkeypatch.setenv("GOOGLE_API_CERTIFICATE_CONFIG", config_filename)
686+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
687+
# Use mock_open to simulate the file in memory
688+
mock_file_handle = mock.mock_open(read_data=config_file_content)
689+
with mock.patch("builtins.open", mock_file_handle):
690+
use_client_cert = _mtls_helper.check_use_client_cert()
691+
assert use_client_cert == "false"
692+
693+
def test_check_use_client_cert_for_workload_with_config_file_no_workload(
694+
self, monkeypatch
695+
):
696+
config_data = {"version": 1, "cert_configs": {"dummy_key": {}}}
697+
config_filename = "mock_certificate_config.json"
698+
config_file_content = json.dumps(config_data)
699+
monkeypatch.setenv("GOOGLE_API_CERTIFICATE_CONFIG", config_filename)
700+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
701+
# Use mock_open to simulate the file in memory
702+
mock_file_handle = mock.mock_open(read_data=config_file_content)
703+
with mock.patch("builtins.open", mock_file_handle):
704+
use_client_cert = _mtls_helper.check_use_client_cert()
705+
assert use_client_cert == "false"
706+
707+
def test_check_use_client_cert_when_file_does_not_exist(self, monkeypatch):
708+
config_filename = "mock_certificate_config.json"
709+
monkeypatch.setenv("GOOGLE_API_CERTIFICATE_CONFIG", config_filename)
710+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
711+
use_client_cert = _mtls_helper.check_use_client_cert()
712+
assert use_client_cert == "false"

0 commit comments

Comments
 (0)